4

精度が約int64_tの範囲内の係数で を補正したいと思います。単純な実装は次のようになります。[0.01..1.2]0.01

int64_t apply_correction(int64_t y, float32_t factor)
{
    return y * factor;
}

残念ながら、 にキャストfactorするint32か、 にキャストすると、精度が失わyfloatます。

ただし、y最大値が 未満1<<56であることを確認できる場合は、次のトリックを使用できます。

(1<<8) * (y / (int32_t)(factor * (1<<8)))

入力値が より大きい場合、この問題をどのように解決できます1<<56か?

プロットツイスト:

int64_tエミュレートされた型であり、倍精度をサポートしていない32 ビット アーキテクチャで実行しています。アーキテクチャは、Analog Devices の SHARC です。

4

3 に答える 3

3

整数空間でそれを行うのはどうですか?

/* factor precision is two decimal places */
int64_t apply_correction(int64_t y, float32_t factor)
{
    return y * (int32_t)(factor * 100) / 100;
}

yこれは、最大値にそれほど近くないと想定していますが、56 ビットより少し近くなります。

于 2016-04-26T09:06:31.160 に答える
3

((int64_t)1 << 57) * 100またはを計算* 256すると、符号付き整数のオーバーフローが発生し、コードが未定義の動作をすることになります。代わりにuint64_tと の値を使用した場合、コードは明確に定義されていますが、明らかに動作が悪いことになります。


ただし、ほぼ までの数に対してこれを機能させることは可能(1 << 63 / 1.2)です。

元の数値を 32 だけ右にシフトされた最上位 32 ビットと最下位 32 ビットに分割できる場合y、これに を掛けます。uint64_t(int32_t)(factor * (1 << 8))

次に、乗算後に最上位ビットを 8 だけ右にシフトするのではなく、24 だけ左にシフトします。次に一緒に追加します:

uint64_t apply_uint64_correction(uint64_t y, float32_t factor)
{
    uint64_t most_significant = (y >> 32) * (uint32_t)(factor * (1 << 8));
    uint64_t least_significant = (y & 0xFFFFFFFFULL) * (uint32_t)(factor * (1 << 8));     
    return (most_significant << 24) + (least_significant >> 8);
}

これで、apply_uint64_correction(1000000000000, 1.2)結果は になり、結果は1199218750000になりapply_uint64_correction(1000000000000, 1.25)ます1250000000000


実際には、次の範囲を保証できれば、より精度を上げることができますfactor

uint64_t apply_uint64_correction(uint64_t y, float32_t factor)
{
    uint64_t most_significant = (y >> 32) * (uint32_t)(factor * (1 << 24));
    uint64_t least_significant = (y & 0xFFFFFFFFULL) * (uint32_t)(factor * (1 << 24));     
    return (most_significant << 8) + (least_significant >> 24);
}

apply_uint64_correction(1000000000000, 1.2)1200000047683私のコンピューターで与えるでしょう。float32_tこれは、仮数部が 24 ビットの場合に取得できる最大精度でもあります。


上記のアルゴリズムは符号付きの正の数に対しても機能しますが、負の数の符号付きシフトは灰色の領域であるため、符号に注意してから、値を に変換し、uint64_t移植可能な計算を行い、元の符号がネガティブ。

int64_t apply_correction(int64_t y, float32_t factor) {
    int negative_result = 0;
    uint64_t positive_y = y;
    if (y < 0) {
        negative_result = 1;
        positive_y = -y;
    }

    uint64_t result = apply_uint64_correction(positive_y, factor);
    return negative_result ? -(int64_t)result : result;
}
于 2016-04-26T09:15:10.123 に答える
2

浮動小数点数を使用しないでください。

int64_t apply_correction(int64_t y, float32_t factor)
{
  int64_t factor_i64 = factor * 100f;

  return (y * factor_i64) / 100ll;
}

y * factor_i64 * 100これは、オーバーフローしないことを前提としています。

于 2016-04-26T09:10:21.293 に答える