金額をセントに変換しようとしていますが、毎回 1 セントずれています。PHP拡張機能を使用せずにこれを行う最良の方法は何ですか?
$amount = 129.95;
$amountInCents = intval(floatval($amount) * 100);
echo $amountInCents; //output: 12994
金額をセントに変換しようとしていますが、毎回 1 セントずれています。PHP拡張機能を使用せずにこれを行う最良の方法は何ですか?
$amount = 129.95;
$amountInCents = intval(floatval($amount) * 100);
echo $amountInCents; //output: 12994
浮動小数点演算と値の格納が不正確であるため ( http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html )、浮動小数点は 129.95 などの多くの値を正確に表すことができません。この場合、192.95 を正確に格納することはできないため、129.9499999 のようになります。
したがって、intval を使用して切り捨てると、12994.999 であることがわかり、12994 に切り捨てられます。
これを解決するには、試すことができます
1) ドルとセントの金額を のような文字列として取得する場合、"$129.95"
文字列解析を使用してドルとセントを整数として計算します。
2) float 値を int に変換する前に 0.00001 のような非常に小さな値を追加します。
3) intval を使用する前にround
http://php.net/manual/en/function.round.phpを使用して、最も近い整数に丸めます。
$amount = 129.95;
echo (string)(floatval($amount) * 100); // cast it to string
すべての数値が浮動小数点で表現できるわけではありません。(たとえば)可能な 64 ビット値は 2 64 個しかないため (エンコーディングでは NaN や無限大などを要求するため、実際の値は少なくなります)、浮動小数点数は無限にあるため、これは明らかです。
詳細については、この回答を参照してください。
したがって、 のような数値は実際129.95
には129.949999999923234
intval(val * 100)
12994
1 つの解決策は、数値を切り捨てるのではなく四捨五入することです。ほとんどの言語では、これを行う方法が多数用意されています。または、次の方法でエミュレートできます。
intval(val * 100 + 0.5);
または、IEEE754 float を使用しないことで問題を回避できます。整数型はおそらく今日では十分に大きいので、これらの種類のエラーが発生しない整数セントを直接格納することができます (計算の複雑さによっては他のエラーが発生する可能性がありますが、浮動小数点に関連するものよりもほぼ確実に少なくなります)点)。
また、より広い範囲が必要な場合は、 BigInteger タイプのパッケージを選択する必要がある場合があります。