1. ホーム
  2. c#

[解決済み] C#でfloat変数が16777216でインクリメントを停止するのはなぜですか?

2022-01-31 01:36:30

質問

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

解決方法は?

IEEE-754浮動小数点数(32ビット)の頭文字をとって短くまとめたものです。

  • 1ビット符号(0は正の数、1は負の数)
  • 8ビットの指数(-127のバイアス付き、ここでは重要ではない)
  • 23ビットの仮数。
  • 指数値0と255の例外を除いて、次のように計算することができます。 (sign ? -1 : +1) * 2^exponent * (1.0 + mantissa)
    • 仮数ビットは バイナリ は、小数点以下の区切り文字です。 1001 0000 0000 0000 0000 000 = 2^-1 + 2^-4 = .5 + .0625 = .5625 で、小数点以下の値は格納されず、暗黙のうちに 1 とみなされます(指数が 255 の場合は 0 とみなされますが、ここでは重要ではありません)。したがって、たとえば指数が 30 の場合、この仮数の例では、次のような値を表します。 1.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
  • そして、問題はここからです。 仮数は値2であってはならない -24 というのは、23ビットしかないので、16777217という数字は32ビット浮動小数点数の精度で表すことができないのです!