如何在PHP中解决这个问题?

时间:2010-01-03 15:08:02

标签: php math floating-point

$onethird = 1.0/3;
$fivethirds = 1.0/3+1.0/3+1.0/3+1.0/3+1.0/3;
$half = 1.0/2;
$threehalf = 1.0/2+1.0/2+1.0/2;
var_dump($onethird + $fivethirds == $half + $threehalf);

输出false,但众所周知:5/3+1/3=2=3/2+1/2

如何解决这个问题?

5 个答案:

答案 0 :(得分:5)

这是浮点数的IEEE 754表示的问题之一;表示不够准确,无法表示所有有理数。

这样做的方法是将差异与非常小的数字进行比较,而不是平等:

abs(($onethird + $fivethirds) - ($half + $threehalf)) < 1e-8

答案 1 :(得分:4)

问题来自Floating Point arithmetic引入的小错误。这不是PHP特有的。

您可以通过引入一个小的“容差”因子来解决这个问题,即通过检查比较中的第一个值是&gt; =第二个值减去公差,&lt; =第二个值加上公差。

答案 2 :(得分:2)

这取决于您的比较应该有多精确
在这种情况下,你应该使用bccomp()而不是“==”
http://php.net/manual/en/language.types.float.php

答案 3 :(得分:1)

var_dump(abs($onethird + $fivethirds - $half + $threehalf) < 0.00001);

见:http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm 还有:http://docs.sun.com/source/806-3568/ncg_goldberg.html

所有编程语言都是如此。

当程序员想要浮点数相等时,我还没有自动完成任何语言。有人应该想出一个新的运算符,也许=〜=浮点相等,它会自动将diff与epsilon进行比较:

if ($float1 =~= $float2) {...

令人讨厌的是,自从我2000年毕业以来,每年的这个时候,一些新手会在一些新闻组,论坛或邮件列表上提出这个问题。就在上个月,我在comp.lang.tcl上回答了这个问题。这不仅仅是新手,两个月前我不得不向我的同事解释这个问题,他已经开发软件超过5年,问我为什么他的Perl代码不起作用。

答案 4 :(得分:1)

  

如何解决这个问题?

您想要解决的实际问题是什么?您的代码只显示浮点数的准确性有限 - 这并不是什么新鲜事。

对于大多数实际应用程序而言,输入无论如何都不是100%准确,结果只需精确到几个小数位。平等比较根本不是大多数时候你需要的。如果你这样做,你可以通过查看结果是否在距离给定数字的某个预定义的小距离内来捏造它。

如果您需要具有特定精度的十进制数学运算,请使用BC Math函数 - 但如果用于复杂计算,则会发现这些函数非常慢。