2011年6月24日金曜日

phpのfloorで値がずれた

いまさらながらPHP(に限った話か?)のfloat(浮動小数点数)の特性にきづかされたのでメモ php.netでおもいっきり注意しろよって書いてあったけど全然 気をつけていなかった。 floatの値を取るデータを扱っている箇所で下二桁までの値を有効として 下三桁を破棄する為の処理を以下のような感じで実装。
$val = 1.10;
echo $val;
$val = floor($val*100)/100;    // (a)
echo $val;
そうすると現象としては こうした場合に結果としては 1.10 1.09 という結果になります。下の値としては1.10を期待していたが、実際には そうならなかった。 これを読み解くと、 floatの特徴として10進数で『0.10』や『0.70』で表現されたデータでも内部的には 2進数である為に、実際には『0.9999....』や『0.6999....』であるらしい。 前述のコードの(a)を分析すると 1)$val*100(浮動小数点数と整数の乗算) ここで内部的には『109.999....』。echo等でテキスト出力すると『110』 2)【(1)】をfloorで小数の切捨て ここで内部的には『109』。echo等でテキスト出力すると『109』 3)【(2)】/100(浮動小数点数の割算) ここで内部的には『1.09』。echoやテキスト値としては『1.09』 という具合になる。 詳しくはphp.netのfloatを読むとスッキリするはず。 ちなみに似た実装や論理で本来の目的を果たしたい場合には 任意精度数学関数またはgmp関数を使えとマニュアルに 書いてあります。 上記に従い取った対策は以下
$val = bcmul($val,100,2) / 100
因みにまだまだ気になる場合にはfloatを使わないという選択肢を選ぶのも また良い選択になりそう。 久しぶりに勉強になった。

0 件のコメント :

コメントを投稿