CodeLab技術ブログ

プログラミング技術まとめ

[PHP]浮動小数点(double/float型)は比較してはいけない

テストロジックを書いていて、意味不明なエラーが発生した。
浮動小数点どうしの比較なのだが、ダンプして数値を見ると一致しているが、IF文で比較するとなぜか不一致になってしまう。
なんじゃこれ?

実は、公式に書いてあった

警告
浮動小数点数値の比較
ふたつの float 値が等しいかどうかを調べてはいけません。 float の内部的な表現方法がその理由です。
詳細な情報は float のドキュメントを参照ください。

比較演算子

例えばこんなことをすると

    $x=0.1;
    $y=1 - 0.9;
    if ($X == $y) {
      printf("同じ値だよ!"); // 実行されない
    }else{
      printf("ちがうよ"); // なぜかこっちが実行される
    }

コードで見ると明らかに同じ数字ですが、計算時の内部誤差により同じ数値になりません。
まぁ、浮動小数点の仕組みを理解していれば、当たり前といえば当たり前の話。

どうしたらいいかというと、このようにします。

    $x=0.1;
    $y=1 - 0.9;
    $epsilon = 0.00001;  //丸め誤差の上界
    if (abs($x-$y)<$epsilon) {
      printf("同じ値だよ!"); 
    }else{
      printf("ちがうよ"); 
    }

二つの値の差をとって誤差が丸め誤差の上界を超えるかどうかを見ます。

また、テスト用ルーチンなどで、いろんなタイプの変数を比較したい場合、いちいち型を調べてソース上で対応するのが面倒っていうときは
gettype()関数で型を調べて分岐させればよさそうです。
なお、諸般の事情でfloat型はdouble型と帰ってくるそうです。

単純に代入したもの同士を比較する分なら、全く同じ値が入るのでいいですが、計算がからむとずれちゃいます。
うっかり普通に比較しちゃいそうで怖いですね。
ワーニングぐらいは出してほしい気がしますね・・・。

コメントは受け付けていません。