floatの履歴
不思議。
<?php $a = 0.4 + 2 / 10; $b = 0.6; var_dump($a); var_dump($b); var_dump($a == $b); var_dump($a === $b);
float(0.6) float(0.6) bool(false) bool(false)
0.1 や 0.7 のようなシンプルな小数であっても、 それを内部的な二進数表現に変換する際には、どうしても多少精度が落ちてしまいます。 その結果、不思議な結果を引き起こすことがあります。たとえば、 floor((0.1+0.7)*10) の結果はたいてい 7 となるでしょう。おそらくは 8 を想定していらっしゃるでしょうが、そのようにはなりません。 これは、(この計算結果の) 内部的な値が 7.9999999999... のようになっているからです。
こうなる理由のひとつとして、「有限小数に変換できない分数がある」 という事実があります。たとえば 1/3 を小数で表そうとすると 0.3333333. . . となります。
よって、小数の最後の桁を信用してはいけませんし、 小数が等しいという比較を行ってはいけません。より高い精度が必要な場合には、 任意精度数学関数または gmp 関数を代わりに使用してください。
1/3とかはダメな感じがするけど、2/10でもダメなんだな。
まてよ、他の言語ではどうだろう。
Java
class CompareFloat{ public static void main(String[] args){ double a = 0.4 + 2d / 10d; double b = 0.6; System.out.println(a); System.out.println(b); System.out.println(a == b); } }
0.6000000000000001 0.6 false
あ、javaでもだめなのか。じゃこれはプログラミング界の常識なのかな?
ってかなんか3年に1度ぐらい同じこと調べてる気がするw
Ruby
a = 0.4 + 2.0 / 10.0; b = 0.6 p a; p b; p a == b;
0.6 0.6 false