我在Magento
、Paybox
和SOAP
web服务中有一个严重的支付错误,其想法如下:
- 付款单位为分$36.37=3637元(
Paybox
-API) -
我想做的是通过以下方式将我的订单价格转换为美分:
$cents = $order->getBaseGrandTotal() * 100;
-
此外,我有一个web服务SOAP(严格类型),它
respond
这个$cents
的数量,但它将其与(int)
协调,然后神奇的是,有时转换的数量不是预期的数量,转换的结果不到一美分,在我的情况下可能是3736
。$prices = array(39.8699, 12.3299, 11.3211); foreach ($prices as $price) { $stuff = round($price, 2) * 100; echo $stuff . PHP_EOL; } echo "After int conversion" . PHP_EOL; foreach ($prices as $price) { $stuff = (int) (round($price, 2) * 100); echo $stuff . PHP_EOL; }
结果如下:
3987
1233
1132
After int conversion
3986
1233
1132
问题有没有办法修复这个bug,它似乎是一个php bug?
您的算法总结如下:
$price = 39.8699; // 39.869900000000001228
round($price, 2) * 100; // 3986.9999999999995453
(int)3986.9999999999995453; // 3986
除了在最后一步中,(int)
的投射会截断外,您在所有地方都是正确的四舍五入。四舍五入更合适:
round($price * 100)
也就是说,根本问题是计算机使用二进制逻辑,通常将数字存储为基数2,而我们人类使用模糊逻辑,更喜欢基数10。"小"整数没有太大问题,因为存在1到1的对应关系,但将任意基数为10的浮点数存储在固定大小的基数为2的表示中通常只是一种近似。一个经典的例子是1.1,它在10进制中有两个数字,但在2进制中是周期性的:
1.0001100110011001100110011001100110011001100110011001100110011001101...
这就是为什么常见的建议包括在可用时使用精确的数据类型(关系数据库中的DECIMAL
,客户端代码中的整数)。