PHP で moneyphp を使って浮動小数点数の誤差を考慮した金額の計算
はじめに
PHP で moneyphp/money を使って浮動小数点数の誤差を考慮した金額を計算する方法。
TL;DR
composer require moneyphp/money
でインストールMoney::JPY(3000)
でインスタンス生成multiply(1.1, Money::ROUND_UP)
で丸めモードを指定して乗算getAmount()
で計算結果の取得String
なので必要に応じて(int)
などでキャスト
- 利用可能であれば 任意精度数学関数 か gmp 関数 を使っても OK
目次
環境・条件
1 | $ cat /etc/os-release |
詳細
前置き
PHP(Laravel)で「消費税込の金額を小数点以下は切り上げで計算」で ceil
を使うと以下のように浮動小数点数の丸め誤差による金額のずれが発生する。
1 | // Psy Shell(artisan tinker)上で計算 |
PHP: 浮動小数点数 にも記載されているが、高精度な処理が必要な場合は 任意精度数学関数 か gmp 関数 を使う必要がある。
gmp 関数を使うには gmp インストール手順 に記載されているように --with-gmp
をつけて PHP のコンパイルが必要。
PHP のコンパイルまではやりたくなかったので、今回この方法は見送り。
※任意精度数学関数(今回で言うと bcmul
や bcdiv
)は PHP のコンパイル無しで利用可能だが作業時に見落としていた。
他のやり方を探して moneyphp/money を見つけたので実際に試してみた。
セットアップ
composer require moneyphp/money
でインストール。
1 | $ composer require moneyphp/money |
使い方
参考: Money for PHP — Money 3.0.0 documentation
※「消費税込の金額を小数点以下は切り上げで計算」に関連するもののみ記載。その他は↑のドキュメント参照。
Money::JPY(3000)
でインスタンスの作成。
1 | use Money\Money; |
multiply
で乗算。
1 | $jpy_with_tax = $jpy->multiply(1.1); |
multiply
の第2引数で丸めモードの指定が可能、デフォルトは ROUND_HALF_UP
。
1 | $jpy_with_tax = $jpy->multiply(1.1, Money::ROUND_UP); |
getAmount
で値の取得。String
で返却されるので、数値型として受け取りたい場合は (int)
でキャストする。
1 | $jpy_with_tax->getAmount(); |
まとめ
composer require moneyphp/money
でインストールMoney::JPY(3000)
でインスタンス生成multiply(1.1, Money::ROUND_UP)
で丸めモードを指定して乗算getAmount()
で計算結果の取得String
なので必要に応じて(int)
などでキャスト
- 利用可能であれば 任意精度数学関数 か gmp 関数 を使っても OK
参考文献
- moneyphp/money: PHP implementation of Fowler’s Money pattern.
- Money for PHP — Money 3.0.0 documentation
- [PHP]浮動小数点数の乗算でハマった話 - Qiita
- PHP: 浮動小数点数 - Manual
- PHP: GMP - Manual
- PHP: GMP インストール手順 - Manual
- PHP: BC Math 関数 - Manual
- PHP: ceil - Manual
関連記事
- Laravel で現在の URL 取得方法まとめ
- Laravel で Cookie を使う(参照/設定/削除)
- Laravel で PDF ファイルをブラウザで開く
- Laravel で withCount と having を使って絞り込み
- PhpSpreadsheet を使って PHP で Excel ファイルの操作(読み込み)
- Laravel で「開始日時 < 終了日時」であることをバリデーションする
- JavaScript で URL のクエリパラメータを操作する方法
- jQuery Select2 で、初期値の設定と選択状態のクリア