2

非定数係数に従って、値をある単位から別の単位に変換する必要があります。入力値の範囲は 0 ~ 1073676289 で、値の範囲は 0 ~ 1155625 です。変換は次のように記述できます。

output = input * (range / 1073676289)

私自身の最初の固定小数点の実装は少しぎこちなく感じます。

// Input values (examples)
unsigned int input = 536838144;  // min 0, max 1073676289
unsigned int range = 1155625;    // min 0, max 1155625

// Conversion
unsigned int tmp = (input >> 16) * ((range) >> 3u);
unsigned int output = (tmp / ((1073676289) >> 16u)) << 3u;

コードを改善して、よりシンプルにしたり、精度を高めたりすることはできますか?

4

4 に答える 4

6

これにより、浮動小数点値なしで最高の精度が得られ、結果は最も近い整数値に丸められます。

output = (input * (long long) range + 536838144) / 1073676289;
于 2012-12-04T15:15:38.553 に答える
5

問題はinput * range、32 ビット整数をオーバーフローさせることです。64 ビット整数を使用して修正します。

uint64_least_t tmp;
tmp = input;
tmp = tmp * range;
tmp = tmp / 1073676289ul;
output = temp;
于 2012-12-04T15:12:50.393 に答える
3

Google に簡単にアクセスしたところ、http: //sourceforge.net/projects/fixedptc/ が気になりました

これは、32 または 64 ビット整数で固定小数点演算を管理するためのヘッダー内の ac ライブラリです。

次のコードで少し実験します。

#include <stdio.h>
#include <stdint.h>

#define FIXEDPT_BITS        64

#include "fixedptc.h"

int main(int argc, char ** argv)
{
    unsigned int input = 536838144;  // min 0, max 1073676289
    unsigned int range = 1155625;    // min 0, max 1155625

    // Conversion
    unsigned int tmp = (input >> 16) * ((range) >> 3u);
    unsigned int output = (tmp / ((1073676289) >> 16u)) << 3u;

    double output2 = (double)input * ((double)range / 1073676289.0);

    uint32_t output3 = fixedpt_toint(fixedpt_xmul(fixedpt_fromint(input), fixedpt_xdiv(fixedpt_fromint(range), fixedpt_fromint(1073676289))));

    printf("baseline = %g, better = %d, library = %d\n", output2, output, output3);

    return 0;
}

次の結果が得られました。

baseline = 577812, better = 577776, library = 577812

コードで取得していたよりも優れた精度を示しています (浮動小数点に一致)。ボンネットの下では、それほど複雑なことは何もしていません (32 ビットではまったく機能しません)。

/* Multiplies two fixedpt numbers, returns the result. */
static inline fixedpt
fixedpt_mul(fixedpt A, fixedpt B)
{
    return (((fixedptd)A * (fixedptd)B) >> FIXEDPT_FBITS);
}


/* Divides two fixedpt numbers, returns the result. */
static inline fixedpt
fixedpt_div(fixedpt A, fixedpt B)
{
    return (((fixedptd)A << FIXEDPT_FBITS) / (fixedptd)B);
}

しかし、それはあなたが望む精度を得ることができることを示しています. それを行うには64ビットが必要です

于 2012-12-04T15:52:00.003 に答える
0

あなたはそれをもっと簡単にすることはありませんoutput = input * (range / 1073676289)

以下のコメントで述べられているように、整数演算に制限されている場合は、次のrange < 1073676289ようrange / 1073676289 == 0になります。

output = range < 1073676289 ? 0 : input

それがあなたが望んでいたものではなく、あなたが実際に精度を望んでいるなら、

output = (input * range) / 1073676289

行く方法になります。

これらの多くを実行する必要がある場合doubleは、コンパイラを使用して操作をベクトル化することをお勧めします。精度も大丈夫です。

于 2012-12-04T15:00:06.557 に答える