我试图将我的美元金额转换为美分,但每次下降一美分。如果不使用任何php扩展,最好的方法是什么?
$amount = 129.95;
$amountInCents = intval(floatval($amount) * 100);
echo $amountInCents; //output: 12994
答案 0 :(得分:4)
由于浮点运算和值存储(http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html)的不准确,浮点不能精确地表示很多值,例如129.95 - 在这种情况下,它类似于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,以便将其四舍五入到最接近的整数。
答案 1 :(得分:4)
$amount = 129.95;
echo (string)(floatval($amount) * 100); // cast it to string
答案 2 :(得分:1)
并非所有数字都可以用浮点表示。这是显而易见的,因为(例如)只有2个 64 可能的64位值(因为编码调用NaN和无穷大之类的东西,所以实际值更少)但是无限数花车。
有关详细说明,请参阅this answer。
因此像129.95
这样的数字_实际上可能类似于129.949999999923234
,当您计算出intval(val * 100)
时,最终会得到12994
。
一个解决方案是舍入数字而不是截断,大多数语言会为您提供多种方法。或者,您可以使用以下方式模拟它:
intval(val * 100 + 0.5);
或者,您可以通过不使用它们来避免IEEE754浮动的问题。现在整数类型可能足够大,你可以直接存储积分美分,这些错误不会发生(可能有其他错误取决于你的计算的复杂性但他们几乎可以肯定少于那些参与浮点的人。)
而且,如果您需要更大的范围,您可以 选择BigInteger类型的包。