問題は、正確な値0.59float
を保持するのに十分な精度がないことです。このような値を格納すると、(コンパイル時にすでに)バイナリ表現で別の値に丸められます。この場合、これは0.59よりわずかに小さい値でした(必要な値よりもわずかに大きい場合もあります)。 )。これに100を掛けると、59よりわずかに小さい値が得られます。このような値を整数に変換すると、0に向かって丸められるため、58になります。
フロートとしての0.59は、次のように格納されます(現在は人間が読める10進数として表されています)。
0.589999973773956298828125
今double
タイプに。このタイプには本質的に同じ問題がありますが、期待される結果が得られる理由は2つあります。希望する正確なdouble
値を保持できる(0.59の場合はそうではありませんが、他の値の場合はそうなる可能性があります)。コンパイラはそれを切り上げることを決定します。したがって、これに100を掛けると、59以上の値になり、予想どおり0から59に丸められます。
double
ここで、aとしての0.59がまだコンパイラによって切り捨てられている場合があることに注意してください。確かに、私はちょうどチェックしました、そしてそれはそうです。0.59は、次のdouble
ように保存されます。
0.58999999999999996891375531049561686813831329345703
ただし、整数に変換する前に、この値に100を掛けています。ここで興味深い点があります。100を掛けると、0.59 * 100を正確に格納できないためy
、コンパイラによる0.59との差がなくなります。実際、プロセッサは計算します。これは59に0.58999999999999996891375531049561686813831329345703 * 100.0
切り上げられます。これは、 !で表すことができる数値です。double
詳細については、次のコードを参照してください:http: //ideone.com/V0essb
ここで、なぜ同じものがカウントされないのか不思議に思うかもしれませんfloat
。これはまったく同じように動作しますが、精度が異なるはずです。問題は、切り上げられない0.589999973773956298828125 * 100.0
ことです(これはで表すこともできます)。計算後の丸め動作は実際には定義されていません。59
float
実際、浮動小数点数の操作は正確に指定されていません。つまり、マシンごとに異なる結果が発生する可能性があります。これにより、丸めが含まれていない場合でも、わずかに不正確な結果につながるパフォーマンスの微調整を実装できます。別のマシンでは期待どおりの結果が得られ、他のマシンではそうではない場合があります。