小数点計算での数値の違い

じつは小数点計算での注意が必要というのを下記サイトからわかりました。
これはよく利用することなので記しておきます。
マニュアルからの引用です。

http://jp2.php.net/manual/ja/language.types.float.php

気をつけておかないといけないポイントになりますね。
これでは計算が合わなくなるので知っておくと今後に役立ちますね。


スポンサーリンク

浮動小数点数の精度
浮動小数点数の精度は有限です。 システムに依存しますが、PHP は通常 IEEE 754 倍精度フォーマットを使います。 この形式は、1.11e-16 のオーダーでの丸め処理で誤差が発生します。 複雑な算術演算をすると、誤差はさらに大きくなるでしょう。そしてもちろん、 いくつかの演算を組み合わせる場合にも誤差を考慮しなければなりません。

さらに、十進数では正確な小数で表せる有理数、たとえば 0.1 や 0.7 は、 二進数の浮動小数点数としては正確に表現できません。 これは、仮数部をいくら大きくしても同じです。 したがって、それを内部的な二進数表現に変換する際には、どうしても多少精度が落ちてしまいます。 その結果、不思議な結果を引き起こすことがあります。たとえば、 floor((0.1+0.7)*10) の結果はたいてい 7 となるでしょう。おそらくは 8 を想定していらっしゃるでしょうが、そのようにはなりません。 これは、(この計算結果の) 内部的な値が 7.9999999999999991118… のようになっているからです。

よって、小数の最後の桁を信用してはいけませんし、 小数が等しいという比較を行ってはいけません。より高い精度が必要な場合には、 任意精度数学関数または gmp 関数を代わりに使用してください。

とあるのですが実際にやってみましょう。

1
2
3
4
5
6
<?php 
if(0.8 === 0.1 + 0.7){
	echo "同じです";
}else{
	echo "違います";
}?>

これは違いますと表示されます。不等号を==に変えてももちろん同じです。

1
<?php echo floor((0.1+0.7)*10)?>

が実は7と表記されるんですね。

1
2
3
4
5
6
<?php 
if(0.8 === 0.8){
	echo "同じです";
}else{
	echo "違います";
}?>

もちろんこれは同じですと表示されます。

1
2
3
4
5
6
<?php 
if(0.8 === 0.3 + 0.5){
	echo "同じです";
}else{
	echo "違います";
}?>

これも同じですと表示されます。
つまり下記の関数を利用するのが良いと言うことですね。

bcadd — 2つの任意精度の数値を加算する
bcsub — 任意精度数値の減算を行う
bcmul — 2つの任意精度数値の乗算を行う
bcdiv — 2つの任意精度数値で除算を行う
bcmod — 2 つの任意精度数値の剰余を取得する
bccomp — 2 つの任意精度数値を比較する
bcscale — すべての BC 演算関数におけるデフォルトのスケールを設定する

1
2
3
4
5
6
7
8
9
10
11
<?php 
$a = 0.8;
$a1 = 0.1;
$a2 = 0.7;
$b = bcadd($a1,$a2,1); 
if (bccomp($a, $b,1)){
    echo "違います";
}else{
    echo "同じです";
}
?>

この問題を解決して分割払いの計算アプリを作成しました。
forで0.1づつ増やすのはfor($i=1;$i<=10;$i=$i+0.1)という風にしました。

デモサイト

Pocket
LINEで送る

スポンサーリンク

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です