私はこの単純なコード行を持っています:
float val = 123456.123456;
この値を出力するか、スコープを調べると、値 123456.13 が格納されます
わかりました。ポイントの後のすべての数字を 4 バイトに格納することはできませんが、なぜポイントの後に 13 になるのでしょうか? 12じゃないの?
(win32 で vc++ 2010 Express を使用)
私はこの単純なコード行を持っています:
float val = 123456.123456;
この値を出力するか、スコープを調べると、値 123456.13 が格納されます
わかりました。ポイントの後のすべての数字を 4 バイトに格納することはできませんが、なぜポイントの後に 13 になるのでしょうか? 12じゃないの?
(win32 で vc++ 2010 Express を使用)
バイナリでは、123456.123456 は 11110001001000000.000111111001... (無限) です。11110001001000000.001 または 123456.125 に丸められます。印刷すると、 123456.13に丸められます。
に格納されている値val
は に等しい123456.125
です。.13
丸めているため、次のようになります。
float val = 123456.123456;
printf("%.4f %.2f\n", val, val);
出力:123456.1250 123456.13
この場合、切り捨てを避けるために double を使用する必要があります。コンパイラは、「警告 C4305: 'initializing': truncation from 'double' to 'float'」 という警告も表示する必要があります。
float として表される場合、数値は 16 の指数を持ちます (つまり、値はその仮数に 2^16 を掛けたもの、つまり 65536 です)。仮数は次のようになります。
123456.123456 / 65536 = 1.8837909462890625
32 ビットの float に収まるように、仮数は 23 ビットに切り捨てられるため、 になり1.883791
ます。を掛け直す65536
と となる123456.125
。
5
小数点の後の 3 番目の位置にある に注意してください。使用した C++ の出力ルーチンによって切り上げられ、最終的な数値は のようになります123456.13
。
EDIT丸めの説明:(Rick Reganのコメント)
丸めは、最初に 2 進数 (24 ビット)、10 進数から 2 進数への変換、次に 10 進数への変換で行われprintf
ます。格納された値は 1.1110001001000000001 x 2^16 = 1.8837909698486328125 x 2^16 = 123456.125 です。123456.13 として出力されますが、これは、Visual C++ が「0 から半分離れて丸める」丸めを使用するためです。
Rick にも、このテーマに関する優れた記事があります。
他の数値とその float 表現を試してみたい場合は、非常に便利な IEEE-754 電卓をご覧ください。
それは完全にコンパイラに依存しています。GCCで確認してください。xxx.12 である必要があります。
の値を出力してみてくださいstd::numeric_limits<float>::digits10
。これは、浮動小数点数が 10 進法でどれだけの精度を持っているかを大まかに表したものです。それを超えようとしているため、精度が失われています (つまり、有効桁数を超える桁は実際には意味がありません)。