When -11.5 plus 11.5 equals float(2.8421709430404E-14)
Possible Duplicate:
PHP Math Precision
Best practice for working with currency values in PHP?
号
我真的希望有人能帮忙。我的头撞在这面砖墙上了。
情况如下:我有一个结帐处,计算出折扣后的小计为11.50英镑。再加上11.50英镑的运费,IMHO应等于0英镑。
但是,当运行计算时,它返回一个浮动2.8421709430404E-14
在我的调试工作中,我做到了:
1 2 3 4 5
| var_dump(
$build['total'], // float(-11.5)
$build['delivery'], // float(11.5)
(($build['total'])+($build['delivery'])) // float(2.8421709430404E-14)
); |
但是,当我进行静态计算时:
号
有什么想法吗?
- 浮点数在设计上有缺陷。这就是为什么与金钱相关的操作应该处理整数,而不是浮点数。
- @是的,完全是。当我结存支票簿时,我总是忽略零碎的美元。
- 也许@raina77ow用"便士数"来写所有的东西?尽管如此,总体观点还是有效的。-)
- +1使用十进制或@ceejayoz建议使用整数便士,并使用$pennies/100显示。
- @但我认为整数不是每次都工作的,就像银行里有利息浮动一样,8.25比怎样用整数来管理它呢?
- 很可能是由于使用float的不精确导致的舍入误差。你应该按照上面的建议使用美分或等值货币。
- @塞杰杰约兹,这就是我想要指出的。在描述如何在与金钱相关的操作中使用整数时,raina77ow不够具体。
- 使用整数。将其存储在1000中。然后将结果除以100,得到整数+/-运算。
- @梅扬克斯瓦米,我想,把硬币和英镑四舍五入是有区别的。)
- @当然,马特,在我看来,这条连接线相当全面。是的,问题是"为什么是0.1+0.2!"=0.3???似乎每天都会出现在这里,所以我看不出复制答案有什么意义。)
- @雷纳77ow,但就像在银行里一样,没有四舍五入的理由,如果以百万为单位的钱比8.25和A更重要,甚至8.25和8.30也重要,那么你会告诉在这个开关中应该怎么做吗?
- 谢谢大家,不过请记住,当我进行静态计算时,结果是正确的。我不相信变整数或四舍五入会有助于解决这个问题。
- @马克,我认为在精确设置中有一些东西,我的php设置和codepad给出0参见codepad.org/5tvwwdkp
2.8421709430404E-14最接近(但不等于)PHP可以输出的零号。它不完全是0的原因在于浮点数的定义——它们从来都不是完全精确的。
如果您需要处理也包含小数点的敏感信息,我建议您将其乘为整数。
所以100.54美元变成了10054美元。在所有的计算完成之后,你就可以把它除以分数。
例子:
1 2 3 4 5 6 7 8 9
| $build['total'] = -11.5;
$build['delivery'] = 11.5;
var_dump(
$build['total'], // float(-11.5)
$build['delivery'], // float(11.5)
(int )($build['total']*1000)+(int )($build['delivery']*1000) // int(0)
(int )(round($build['total'], 4)*1000)+(int )(round($build['delivery'], 4)*1000) // int(0)
); |
- 整数产生精确的值。但是你不能有任何分数,最大值相对较小。浮点数允许您具有分数、非常大的值和非常小的值…但是浮点数总是一个近似值:php浮点数:警告
- 好吧,那不是基于设置吗?代码板.org/5tvwwdkp
- @Inori我在发布问题之前确实尝试过这个方法,但是它返回了相同的结果。正如我提到的,如果我用静态值进行计算,结果是正确的。只有当我使用我的真值时,当我使用1(0)时,内容是相同的。
- @痘-正是我的观点。有什么想法,为什么当我变量转储变量时,它们是浮动的,但是计算失败了?
- @马克·史密斯:请看这个链接:在PHP中使用金钱的最佳实践,2)接受inori的答案。
- @马克史密斯用示例更新了我的帖子
- @Inori-谢谢,我的代码是(int)($build['total']*1000)+(int)($build['delivery']*1000) // int(1)。
- @马克史密斯,这很有趣,我想不同的设置处理(int)不同。不管怎样,请参阅更新的示例,这将在任何系统上产生正确的答案。
- 实际上,我会这样做:(int)($build['total']+$build['delivery'])*1000.0)。换句话说,最后强制转换为"int"。
- @Paulsm4是的,在这种情况下,您的解决方案更好。我只是假设数据已经从模型中生成,即在现实世界中,我的示例看起来像这个$order->getPreciseTotal() + $order->getPreciseDelivery()
- 好的,现在分类。部分感谢@inori。我最后四舍五入到小数点后两位。埃多克斯1〔5〕