比较双精度的奇怪行为,两个PHP双精度值不等价

bwitn5fc  于 2023-03-16  发布在  PHP
关注(0)|答案(5)|浏览(106)

我在PHP中有两个看似相等的双精度值(至少在回显它们时)。
但是当它们与double equals比较时,由于某种原因,它的计算结果为false,在执行这种比较时有什么特殊的考虑吗?

kuarbcqp

kuarbcqp1#

不应使用==运算符比较浮点数。
请参见重要警告和explanation in the php manual
有效的方法是Assert这两个数字彼此之间的距离在某个小范围内,就像这样:

if(abs($a - $b) < 0.0001) {
    print("a is mostly equal to b");
}

这是由于在将小数转换成二进制后再转换回小数时进行的浮点运算所引起的舍入误差,这些来回转换会导致0.1 + 0.2不等于0.3的现象。

slmsl1lt

slmsl1lt2#

float和double绝对不能比较是否相等:存在精度误差,即使两个数字看起来相等,它们也会不同(当它们被打印出来时,它们通常是四舍五入的)。
比较的正确方法是使用某个DELTA常数:

define(DELTA, 0.00001); // Or whatever precision you require

if (abs($a-$b) < DELTA) {
  // ...
}

还请注意,这不是PHP特有的,但在其他语言(Java、C ...)中也很重要。

e7arh2l6

e7arh2l63#

不是最快的方法,但在比较之前转换为字符串:

if( strval($a) === strval($b) ){
  // double values are exactly equal
}
3npbholx

3npbholx4#

PHP(as well as in C and many other languages)中浮点数的表示是不精确的。由于这个事实,看似相等的数字实际上可能是不同的,比较将失败。相反,选择一些小的数字,并检查差异是否小于这个数字,如:

if(abs($a-$b)<0.00001) {
  echo "Equal!";
}

另请参见explanations in the PHP manual

jdgnovmf

jdgnovmf5#

我做了一个小函数,希望能帮助别人:

function are_doubles_equal($double_1, $double_2, $decimal_count) {
    if (!$decimal_count || $decimal_count < 0) {
        return intval($double_1) == intval($double_2);
    }
    else {
        $num_1 = (string) number_format($double_1, $decimal_count);
        $num_2 = (string) number_format($double_2, $decimal_count);
        return $num_1 == $num_2;
    }
}

用法:

$a = 2.2;
$b = 0.3 + 1.9002;
  
are_doubles_equal($a, $b, 1); // true : 2.2 == 2.2 
are_doubles_equal($a, $b, 1); // false : 2.2000 == 2.2002

相关问题