いまさらながら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 件のコメント :
コメントを投稿