我试图将我的美元金额转换为美分,但每次都会减少一美分。不使用任何 php 扩展的最佳方法是什么?
$amount = 129.95;
$amountInCents = intval(floatval($amount) * 100);
echo $amountInCents; //output: 12994
我试图将我的美元金额转换为美分,但每次都会减少一美分。不使用任何 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 - in在这种情况下,它类似于 129.9499999,因为它不能完全存储 192.95。
因此,当您使用 intval 向下舍入时,它会看到您有 12994.999... 并向下舍入为 12994。
要解决这个问题,您可以尝试
1)如果您将美元和美分金额作为字符串,例如"$129.95"
,使用字符串解析将美元和美分计算为整数
2) 在将浮点值转换为 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
并非所有数字都可以用浮点数表示。这很明显,因为(例如)只有 2 64 个可能的 64 位值(实际值较少,因为编码需要诸如 NaN 和无穷大之类的东西),但浮点数是无限的。
请参阅此答案以获取更多说明。
所以像这样的数字129.95
实际上可能是这样129.949999999923234
的,当你锻炼时intval(val * 100)
,你最终会得到12994
.
一种解决方案是对数字进行舍入而不是截断,大多数语言都会为您提供多种方法来做到这一点。或者,您可以使用以下方法模拟它:
intval(val * 100 + 0.5);
或者,您可以通过不使用 IEEE754 浮点数来避免它们的问题。现在整数类型可能已经足够大了,您可以直接存储整数美分,而不会发生此类错误(根据计算的复杂性,可能还有其他错误,但它们几乎肯定会小于浮点数观点)。
而且,如果您需要更大的范围,您可能必须选择 BigInteger 类型的包。