0
0

More than 3 years have passed since last update.

PHPの数値計算メソッドが物足りなかったため自作

Last updated at Posted at 2021-02-09

本記事の環境

ホストOS:Windows 10
ゲストOS:CentOS 7
VirtualBox + Vagrant
Tera Term
remiリポジトリ
php7.3

前段:PHPの数値計算系メソッドとは?

PHPには四捨五入、切り上げ、切り下げのメソッドが存在します。
※四捨五入:round、切り上げ:ceil、切り下げ:floor

要件1:数値の丸め方について

  • 「四捨五入」「切り上げ」「切り下げ」と「切り捨て」がしたい。
  • 有効桁数を指定したい。

問題

  • 他言語にある「切り捨て」がPHPにはなかった。
  • roundは、有効桁数を指定できるが、ceilとfloorはできない。
    ※round([対象値], [有効桁数]);
      有効桁数:小数第一位が0、小数部はそこからインクリメント、
           整数部はデクリメント。
    ※ceil([対象値]);
    ※floor([対象値]);

対処方法

  • 「切り捨て」メソッドを作る。
  • 有効桁数を指定できる「切り上げ:ceil」「切り下げ:floor」メソッドを作る。
    ※実装方法はネット上に複数パターン存在します。
      ※例1:補正値を加算してから処理を実施し、後で補正値を取り除く。
      ※例2:桁数を落として小数部を取り除いてから桁数を戻す。

要件2:計算結果について

  • 正しい計算結果を出したい。

問題

  • 2進数で表せない値を与えると結果に丸め誤差が生じる。(他言語も同様)
    
    floor((0.1 + 0.7) * 10);       // 結果:7 (7.999999999999…に対して切り下げ処理を実施。)
    floor((0.1 + 0.7 + 0.5) * 10); // 結果:12 (12.999999999999…に対して切り下げ処理を実施。)
    

対処方法

  • BCMathライブラリ(任意精度数学関数)を使うことにした。
    
    yum install --enablerepo=remi-php73 php-bcmath
    systemctl restart httpd
    

その他注意点

  • -0.5よりも大きく、0未満の負の数についてroundを使用すると「-0」へ変換される。
    
    round(-0.49999999999999, 0); // 結果:-0 (絶対値の0.49999999999999を四捨五入して、その結果にマイナスをつけるため。)
    
  • 丸め誤差が生じるため、float(浮動小数点数値)同士の比較はやめた方がいい。文字列型にキャストして比較するか、bccomp()を使用するか、gmp()を使用するか。

まとめ

PHPで数値計算を行う場合は、十分な仕様理解と(自作する場合は)作業工数が必要。

参考

https://gotohayato.com/content/491
https://www.sejuku.net/blog/25405
https://www.sejuku.net/blog/48961
https://teratail.com/questions/11119
http://shiru-web.com/2018/04/14/01-81/
https://web-dev.xyz/php-round/

0
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0