kazu22002の技術覚書

PHPer, Golang, AWS エンジニアの日々

PHPの数値について考える(3)

浮動小数点数のページを見た後、整数の項目で気になるのがありました。

 echo (int) ( (0.1+0.7) * 10 )."\n"; // 7が出力されます!

 

これって本当!?

って、ことで試してみました。

 

本当に「7」だ。

 

説明は浮動小数点数の精度で書いてあります。

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

 なるほど。納得です。

 

というわけで、すこし実験。

(int) ( (0.1+0.7) * 10 )
echo ( (0.1+0.7) * 10 );
echo ( (0.1 * 10) + (0.7* 10 ));
(int)( (0.1 * 10) + (0.7* 10 ))
$a = "0.1";
$b = "0.7";
echo (($a+$b) * 10 );
echo (int) (($a+$b) * 10 );
$c = ((0.1+0.7) * 10 );
echo $c;
echo (int)$c;
echo (int)floor($c);
echo (int)ceil($c);

結果

7  // サンプル
8  // キャストなし 
8  // わけて計算

8 // キャストあり。分けて計算
8 // 変数でやってみた
7 // キャストあり。変数でやってみた
8 // 計算結果を変数に代入
7 // キャストあり。計算結果を変数に代入
7 // 少数点以下を切り捨て
8 // 少数点以下を切り上げ

 

 計算結果を代入した後のキャストありとなしはすごい気になった。

確かに計算結果を保持していると納得。

計算結果的に切り上げの判断が下されているところがすごく怖い。

 var_dump($c);

結果

float(8)

 

PHPで計算するのが怖くなってしまった。。。