【问题标题】:Odd behavior comparing doubles, two PHP double values aren't equivalent比较双精度的奇怪行为,两个 PHP 双精度值不等价
【发布时间】:2011-03-11 09:21:16
【问题描述】:

我在 PHP 中有两个看似相等的 double 值(至少在回显它们时)。

但是当将它们与双等号进行比较时,由于某种原因,它的评估结果为假。进行此类比较时是否有任何特殊注意事项?

【问题讨论】:

  • 你能发布你正在使用的代码和那些双打吗?

标签: php compare double


【解决方案1】:

您不应使用 == 运算符比较浮点数。

查看大警告和explanation in the php manual

有效的方法是断言这两个数字彼此之间存在一定的小距离,如下所示:

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

原因是小数转换为二进制后再转换回十进制后进行浮点运算导致舍入错误。这些来回转换导致0.1 + 0.2不等于0.3的现象。

【讨论】:

    【解决方案2】:

    float 和 double 永远不应该比较相等:存在精度错误,即使它们看起来相等,也会使两个数字不同(当它们被打印出来时,它们通常是四舍五入的)。

    比较的正确方法是使用一些 DELTA 常量:

    define(DELTA, 0.00001); // Or whatever precision you require
    
    if (abs($a-$b) < DELTA) {
      // ...
    }
    

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

    【讨论】:

      【解决方案3】:

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

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

      另见explanations in the PHP manual

      【讨论】:

        【解决方案4】:

        我做的一个小功能,希望对大家有所帮助:

        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
        

        【讨论】:

          【解决方案5】:

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

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2023-03-11
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2022-10-01
            • 2012-11-03
            • 2015-12-17
            相关资源
            最近更新 更多