サーチ…
浮動小数点数は奇妙です
ほとんどすべてのプログラマーが最初に間違いを犯すのは、このコードが意図したとおりに動作することを前提としています。
float total = 0;
for(float a = 0; a != 2; a += 0.01f) {
total += a;
}
初心者のプログラマは0, 0.01, 0.02, 0.03, ..., 1.97, 1.98, 1.99
の範囲内のすべての単一の数値を合計して結果199
を得ると仮定します。これは数学的に正解です。
これを真実に見せかける2つのことが起こります:
- 書かれたプログラムは決して終わらない。
a
は決して2
に等しくなく、ループは決して終了しません。 - 代わりに
a < 2
をチェックa < 2
ループロジックを書き換えると、ループは終了しますが、合計は199
とは異なる値になります。 IEEE754に準拠しているマシンでは、多くの場合約201
が加算されます。
これが発生する理由は、 浮動小数点数が割り当てられた値の近似を表すためです 。
古典的な例は、次の計算です。
double a = 0.1;
double b = 0.2;
double c = 0.3;
if(a + b == c)
//This never prints on IEEE754-compliant machines
std::cout << "This Computer is Magic!" << std::endl;
else
std::cout << "This Computer is pretty normal, all things considered." << std::endl;
プログラマが見るものは、base10で書かれた3つの数字ですが、コンパイラ(とその基礎となるハードウェア)にはバイナリの数字があります。ので、 0.1
、 0.2
、および0.3
完全除算必要と10
ベース2の基地-10システムでは非常に簡単である-whichが、不可能をシステムこれらの数字は同様に、不正確な形式で格納する必要がどのように数1/3
は、基数10の不正確な形式0.333333333333333...
に格納する0.333333333333333...
。
//64-bit floats have 53 digits of precision, including the whole-number-part.
double a = 0011111110111001100110011001100110011001100110011001100110011010; //imperfect representation of 0.1
double b = 0011111111001001100110011001100110011001100110011001100110011010; //imperfect representation of 0.2
double c = 0011111111010011001100110011001100110011001100110011001100110011; //imperfect representation of 0.3
double a + b = 0011111111010011001100110011001100110011001100110011001100110100; //Note that this is not quite equal to the "canonical" 0.3!
Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow