61
float a = 0;
while (true)
{
    a++;
    if (a > 16777216)
        break; // Will never break... a stops at 16777216
}

このコードで float 値が 16777216 で増加しなくなる理由を誰かに説明してもらえますか?

編集:

またはさらに単純です:

float a = 16777217; // a becomes 16777216
4

4 に答える 4

69

頭のてっぺんからのIEEE-754浮動小数点数(32ビット)の短いまとめ:

  • 1 ビット符号 (0 は正の数、1 は負の数を意味します)
  • 8 ビット指数 (-127 バイアスあり、ここでは重要ではありません)
  • 23ビットの「仮数」
  • 指数値 0 と 255 を除いて、値は次のように計算できます。(sign ? -1 : +1) * 2^exponent * (1.0 + mantissa)
    • 仮数ビットは、小数点の後の2 進数を表します。たとえば、小数点の前の値は格納されませんが、暗黙的に 1 と見なされます (指数が 255 の場合、0 が想定されますが、ここでは重要ではありません)。たとえば、この仮数の例は値を表します。1001 0000 0000 0000 0000 000 = 2^-1 + 2^-4 = .5 + .0625 = .56251.5625

今あなたの例に:

16777216 は正確に 2 24であり、次のように 32 ビット浮動小数点として表されます。

  • 符号 = 0 (正の数)
  • 指数 = 24 (24+127=151= として格納10010111)
  • 仮数 = .0
  • 32 ビット浮動小数点表現として:0 10010111 00000000000000000000000
  • したがって: 値 =(+1) * 2^24 * (1.0 + .0) = 2^24 = 16777216

では、16777217 という数字、つまり 2 24 +1を見てみましょう。

  • 符号と指数が同じ
  • 仮数は正確に 2 -24でなければならないので、(+1) * 2^24 * (1.0 + 2^-24) = 2^24 + 1 = 16777217
  • そして、ここに問題があります。仮数は 23 ビットしかないため、値 2 -24を持つことはできません。したがって、数値 16777217 を 32 ビット浮動小数点数の精度で表現することはできません!
于 2012-09-26T09:15:01.640 に答える
17

16777217 は float では正確に表すことができません。float が正確に表すことができる次に大きい数値は 16777218 です。

したがって、float 値 16777216 を 16777217 にインクリメントしようとしますが、これは float では表すことができません。

于 2012-09-26T07:33:41.493 に答える
13

その値を 2 進表現で見ると、1 と多数のゼロ、つまり1 0000 0000 0000 0000 0000 0000、正確に 2^24 であることがわかります。つまり、16777216 で、数字が 1 桁増えただけです。

これは浮動小数点数であるため、これは、まだ格納されている (つまり、精度の範囲内である) 末尾の最後の桁も左にシフトされることを意味します。

おそらく、あなたが見ているのは、精度の最後の桁が 1 よりも大きいものにシフトしたため、1 を追加しても、もはや何の違いも生じないということです。

于 2012-09-26T07:34:05.527 に答える