PHPの演算誤差

(2/3)

BCMath任意精度数学関数

PHP には、BCMath 任意精度数学関数という関数群が用意されている。これは、10進数表記された数字に対して任意精度の演算を提供するものである。

サンプル・プログラム

プログラムを実行する

ダウンロード(PHP4/5共用)

サンプル・プログラムの解説

0001: <?php
0002: /** marginerror2.php
0003:  * BCMath任意精度数学関数の利用例
0004:  * @copyright (c)studio pahoo
0005:  * @author     パパぱふぅ
0006:  * @version     1.0 2006/12/06
0007: */
0008: bcscale(10);       //有効桁数を10桁にする
0009: //小数乗算
0010: $a = 10000;
0011: $b = 70.21;
0012: $x = bcmul($a$b);
0013: printf("%s×%s=%d<br />", $a$b$x);
0014: 
0015: //循環小数
0016: $a = 1;
0017: $b = 3;
0018: $x = bcdiv($a$b);
0019: printf("%s÷%s=%f<br />\n", $a$b$x);
0020: $x = bcmul($x$b);
0021: printf("%s÷%s×%d=%d<br />\n", $a$b$b$x);
0022: ?> 

サンプル・プログラムを実行すると、結果は、期待したとおりの 702100 となった。
まず、関数  bcscale  で有効桁数を指定する(8行目)。関数  bcscale  は任意精度の乗算である(12行目)。
space
ところが、今度は循環小数の計算で問題が起きてしまう。
除算を行う関数  bcdiv  の段階(18行目)で、変数 $x には有効桁数 10 桁の 10進数――0.3333333333――が代入される。このため、次の乗算の段階(20行目)で、0.9999999999 となってしまう。
関数  printf  の修飾子 %d や %f を %s に変更してもらえれば、このあたりの内部状況がよく分かるだろう。
この項つづく
header