web-dev-qa-db-ja.com

PHPで通貨値を操作するためのベストプラクティスは?

PHPの通貨値を加算、乗算、比較する必要があり、1セントまで正確であることを確認する必要があります。

1つの方法は、すべてをフロートに格納し、各操作の前後にラウンドを使用し、同等性を比較するときにマインドマシンイプシロンを使用することです。かなり面倒な私見。

もう1つの方法は、すべてをセントとして整数データ型に格納することです。さらに、データベース(mysql、10進データ型を使用)で作業するときはいつでも前後に変換することを忘れないでください。エレガントではなく、多くのエラーの落とし穴、私見。

もう1つの方法は、独自の「データ型」を作成し、すべての値を文字列( "34.12")に格納して、独自の数学的置換関数を作成することです。これらの関数は、値を内部で整数に変換し、計算を実行して、結果を再び文字列に出力します。驚くほど複雑な、私見。

私の質問:PHPで通貨値を操作するためのベストプラクティスは何ですか?ありがとう!

33
CruftyCraft

これに自分で答えさせてください。ベストプラクティスは、「金額」クラスを作成することです。このクラスは、金額を整数のセントとして内部的に格納し、ゲッター、セッター、加算、減算、比較などの数学関数を提供します。はるかにきれい。

4
CruftyCraft

MySQL v5.0.3以降、MySQL DECIMALデータ型は正確な10進数を格納します。つまり、不正確な浮動小数点表現ではありません。

PHPの精度の数値を正しく操作するには、 任意精度の数学関数 を使用します。内部的に、このライブラリはテキスト文字列を操作します。

通貨は10進数として保存されることを目的としており、セントよりも小さい単位を取得できます。操作や保存中ではなく、図を表示するときにのみ値を丸める必要があります。

25
Randy the Dev

2016年更新:

数年後、うまくいけば少し賢くなります;)
この回答はまだ時折賛成票と反対票を獲得しているので、回答を修正する必要があると感じました。 'money'を整数として保存することは絶対にお勧めしません。唯一の正解はAndrewDunnです。MysqlのDECIMAL型を使用し、phpのbc_ *関数をCurrencyクラスにカプセル化します。


完全を期すために、古い回答はここに残しておきます

常に整数を使用する必要があります。値をintとしてデータベースに保存し、intを使用して計算を行い、印刷する場合にのみ、読み取り可能な形式に変換します。

このようにして、浮動小数点の問題を完全に回避できます。これは、一般に、お金を扱うときに大きな問題になります;)

編集:言及する価値のあることの1つ:この方法で作業を開始する前に、精度について考える必要があります。他の人が指摘しているように、1セント未満の値で作業する必要があるかもしれないので、それに応じて乗算/除算を行う必要があります。 (つまり、.001の精度の場合は通貨* 1000)

3

値をセントとして保持し、整数を使用します。 UIでの表示とデータベースクエリでの値の処理をカプセル化するクラスまたはヘルパー関数を記述します。フロートを使用すると、どこかで1セントを失うリスクが多すぎます。

0
Matthew Smith

すべての数学演算の前にfloatに100を掛けてから、結果を表示する前に100で割ってみました。 (機能した!)

数学的には、これは他の人が示唆しているように「整数への変換」ですが、コードは変換関数なしではるかにエレガントに見えます。また、混乱を避けるために、値の名前の末尾に「セント」を追加しました。

マシン側からは、floatの代わりに整数を使用する方がおそらく高速ですが、人間が読めるコードを書くことは私の解決策を好みます。 (マイレージは異なる場合がありますが、私のアプリケーションでは機能しました。)