5

FPUの現在の丸めモードについて何も変更したり、想定したりせずdoubleに、IEEE 754をすぐに劣る(または優れた)floatに変換するためのコードのスニペットを手元に持っている人はいますか?

注: この制約は、おそらく FPU をまったく使用しないことを意味します。これらの条件でそれを行う最も簡単な方法は、倍精度のビットを 64 ビットの長さで読み取り、それを操作することだと思います。

簡単にするために、選択したエンディアンを想定できます。また、問題の double は、d以下の共用体のフィールドを介して使用できると想定できます。

union double_bits
{
  long i;
  double d;
};

私はそれを自分でやろうとしますが、非正規化または負の数に対して気づきにくいバグを導入することは確かです.

4

3 に答える 3

3

仮数と指数ビットを再結合するよりも正確にこの仕事を行うには、これをチェックしてください:

http://www.mathworks.com/matlabcentral/fileexchange/23173

よろしく

于 2010-01-06T10:01:20.080 に答える
3

私は次のように動作すると思いますが、最初に私の仮定を述べます。

  • 浮動小数点数は、実装で IEEE-754 形式で格納されます。
  • オーバーフローなし、
  • nextafterf()利用可能です(C99で指定されています)。

また、ほとんどの場合、この方法はあまり効率的ではありません。

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

int main(int argc, char *argv[])
{
    /* Change to non-zero for superior, otherwise inferior */
    int superior = 0;

    /* double value to convert */
    double d = 0.1;

    float f;
    double tmp = d;

    if (argc > 1)
        d = strtod(argv[1], NULL);

    /* First, get an approximation of the double value */
    f = d;

    /* Now, convert that back to double */
    tmp = f;

    /* Print the numbers. %a is C99 */
    printf("Double: %.20f (%a)\n", d, d);
    printf("Float: %.20f (%a)\n", f, f);
    printf("tmp: %.20f (%a)\n", tmp, tmp);

    if (superior) {
        /* If we wanted superior, and got a smaller value,
           get the next value */
        if (tmp < d)
            f = nextafterf(f, INFINITY);
    } else {
        if (tmp > d)
            f = nextafterf(f, -INFINITY);
    }
    printf("converted: %.20f (%a)\n", f, f);

    return 0;
}

私のマシンでは、次のように出力されます。

Double: 0.10000000000000000555 (0x1.999999999999ap-4)
Float: 0.10000000149011611938 (0x1.99999ap-4)
tmp: 0.10000000149011611938 (0x1.99999ap-4)
converted: 0.09999999403953552246 (0x1.999998p-4)

double値を値に変換するという考え方ですfloat。これは、丸めモードに応じて double 値よりも小さい場合も大きい場合もあります。に戻すとdouble、元の値より小さいか大きいかを確認できます。次に、 の値がfloat正しい方向にない場合はfloat、変換された数値から元の数値の方向に次の数値を調べます。

于 2010-01-07T03:07:04.273 に答える
2

これを行うコードをhttps://stackoverflow.com/q/19644895/364818に投稿し、便宜上以下にコピーしました。

    // d is IEEE double, but double is not natively supported.
    static float ConvertDoubleToFloat(void* d)
    {
        unsigned long long x;
        float f; // assumed to be IEEE float
        unsigned long long sign ;
        unsigned long long exponent;
        unsigned long long mantissa;

        memcpy(&x,d,8);

        // IEEE binary64 format (unsupported)
        sign     = (x >> 63) & 1; // 1
        exponent = ((x >> 52) & 0x7FF); // 11
        mantissa = (x >> 0) & 0x000FFFFFFFFFFFFFULL; // 52
        exponent -= 1023;

        // IEEE binary32 format (supported)
        exponent += 127; // rebase
        exponent &= 0xFF;
        mantissa >>= (52-23); // left justify

        x = mantissa | (exponent << 23) | (sign << 31);
        memcpy(&f,&x,4);

        return f;
    }
于 2013-10-28T20:58:59.667 に答える