Upgrade to Pro — share decks privately, control downloads, hide ads and more …

PHPで任意精度演算を行って「正しい」金額計算をする方法 / Perform arbitrar...

PHPで任意精度演算を行って「正しい」金額計算をする方法 / Perform arbitrary precision arithmetic in PHP to achieve "accurate" monetary calculations

Avatar for YAMAOKA Hiroyuki

YAMAOKA Hiroyuki

March 24, 2023
Tweet

More Decks by YAMAOKA Hiroyuki

Other Decks in Programming

Transcript

  1. 0.1 + 0.2 ≠ 0.3 php > var_dump(0.1 + 0.2);

    float(0.30000000000000004) 🤔
  2. fl oat / double - PHPで、整数は int(integer)という型 - 10進数、16進数、8進数、2進数で指定可能 -

    「整数以外」を表現するのに浮動小数点数を使う - fl oat(ただし倍精度)、double - intの上限(PHP_INT_MAX)を超える整数も対象
  3. 2進数の世界 - コンピューターは2進数で動いている - 0 or 1(OFF or ON)のバイナリの世界 -

    10進数の小数は2進数の世界で表現可能か? - 0.1(2進数)は2-1(10進数の0.5) 
 0.01(2進数)は2-2(10進数の0.25)
  4. 浮動小数点数 - 10進数の実数を有限桁の2進数の近似値で表現 - 浮動小数点( fl oating-point) - -1 x

    0.101010101010101 x 2-1 と 
 -1 x 1.01010101010101 x 2-2 は同じ 
 符号、仮数、指数 - 複数フォーマットがある(そのうちの1つがIEEE 754)
  5. BC Math 関数 - GNU bc(Basic Calculator)からのfork - https://www.gnu.org/software/bc/ -

    PHPを「--enable-bcmath」を付けて構築 - 関数: bcadd、bccomp、bcdiv、bcmod、bcmul、 bcpow、bcpowmod、bcscale、bcsqrt、bcsub
  6. 例えば足し算 php > var_dump(bcadd('0.1', '0.2', 1)); string(3) "0.3" php >

    var_dump(bcadd('0.1', '0.2', 20)); string(22) "0.30000000000000000000"
  7. GMP 関数 - GNU Multiple Precision Arithmetic Library - https://gmplib.org/

    - PHPを「--with-gmp」を付けて構築 - とてもたくさんの数学関数群
  8. 雑なベンチマーク <?php $floatStart = microtime(true); for ($i = 0; $i

    < 10000000; $i++) { $result = 0.1 + 0.2; } $floatEnd = microtime(true); $bcStart = microtime(true); for ($i = 0; $i < 10000000; $i++) { $result = bcadd('0.1', '0.2', 1); } $bcEnd = microtime(true); echo 'float: ' . ($floatEnd - $floatStart) . "ms\n"; echo 'bcadd: ' . ($bcEnd - $bcStart) . "ms\n";
  9. 注意: 引数は文字列で - BC Math関数に渡す引数は「文字列」で - fl oat表記で渡すとstringにキャストされる - 例:

    0.00001 は 1.0E-5 になってしまう - 数値を表す文字列ではないのでエラーになる可能性
  10. ただし - BC Math関数に用意されているのは 
 基本的な算術関数のみであることに注意 - 例えば、 fl oorやceil、roundのような関数はない

    - 雑に fl oor関数等に渡すと fl oatに変換されるので 
 計算誤差が発生する可能性がある