次のコードで:
float f = 23.456;
printf("%f", f);
のさまざまな値の出力は次のf
とおりです。
Value Output
--------- --------
f = 23.456 23.455999
f = 23.956 23.955999
f = 23.947 23.947001
f = 23.656 23.656000
得られた値が予測できない、またはパターンがあるのはなぜですか?
これは、すべてのプログラマーが浮動小数点について知っておくべきことのカテゴリに分類されます。浮動小数点が機能する方法は、一部の数値が浮動小数点で完全に表現できないことを意味します。これを説明する最も簡単な方法は、値 1/3 を 10 進数として書き留めてもらうことです。最初はとても幸せそうに見えますが、最終的には紙がなくなります。この理由は、10 進数表記では数値 1/3 が無限に長いため、数値を格納するために 10 進数表記を使用する適切なエンコード システムでは、その長さに制限があるためです。
浮動小数点も同じことを行いますが、基数 2 を使用します。これは、1/10 や 0.1 など、私たちにとって非常に単純に見える数が無限に再帰的になることを意味します。これにより、数値を出力するときに丸めエラーが発生します。これは、数値を格納できなかったため、格納した数値がコンパイラに与えた数値ではないためです。
これに関する標準的な論文はhttp://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.htmlです。これは非常に読みにくいですが、これらすべてとさらに多くのことを説明しています。
これは、浮動小数点数を格納するために C で使用されるIEEE 754 32 ビット浮動小数点形式によるものです。あなたが持っている仮数はバイナリに変換され、float
変数が必要とする 4 バイト空間の下位 23 ビットに格納されます。正確なバイナリに完全に変換できる場合もあれば、正確に変換できない場合もあるため、切り捨てられた形式の数値が格納されます。これは、メモリから読み取ると、わずかに異なる値に評価されます。
1/3
この動作は、精度の要件に応じて、値を 0.33 または 0.333 として使用する数学と似ています。
使用してみてください:
f = 0.25;
または、
f = -15.625;
または、正確に 2 進数に変換可能な 10 進数値であれば、正しい結果が得られます。