是围绕一个正确的方式进行浮动 - 双重比较

时间:2014-01-30 16:18:45

标签: c++ performance algorithm comparison

this问题为基础,众所周知,我们不应将等于比较运算的十进制变量应用于数字错误(它不受编程语言约束):

bool CompareDoubles1 (double A, double B)
{
   return A == B;
}

abouve代码不对。 我的问题是:

  1. 将这两个数字四舍五入然后进行比较是正确的吗?
  2. 效率更高?
  3. 例如:

    bool CompareDoubles1 (double A, double B)
        {
           double a = round(A,4);
           double b = round(B,4)
           return a == b;
        }
    

    这是对的吗?

    修改

    我正在考虑round是一个采用double(number)和int(precition)的方法:

    bool round (float number, int precision);
    

    修改 我认为用这个比较方法可以更好地理解我对这个问题的意思:

    bool CompareDoubles1 (double A, double B, int precision)
            {
               //precition could be the error expected when rounding
               double a = round(A,precision);
               double b = round(B,precision)
               return a == b;
            }
    

6 个答案:

答案 0 :(得分:5)

通常,如果您真的需要比较浮动值,则需要指定容差:

bool CompareDoubles1 (double A, double B, double tolerance)
{
   return std::abs(A - B) < tolerance;
}

选择合适的容差取决于值的性质和产生它们的计算。

舍入是不合适的:两个非常接近的值,你想要比较相等,可能会在不同的方向上舍入并且看起来不相等。例如,当舍入到最接近的整数时,0.30.4会比较相等,但0.4999990.500001则不会。

答案 1 :(得分:4)

双打的常见比较实现为

bool CompareDoubles2 (double A, double B)
{
   return std::abs(A - B) < 1e-6; // small magic constant here
}

它显然不如支票A == B有效,因为它涉及更多步骤,即减法,调用std :: abs并最终与常量进行比较。

关于效率的相同论点适用于您提出的解决方案:

bool CompareDoubles1 (double A, double B)
{
   double a = round(A,4); // the magic constant hides in the 4
   double b = round(B,4); // and here again
   return a == b;
}

同样,这不会像直接比较那样有效,但是 - 再次 - 它甚至不会尝试做同样的事情。

CompareDoubles2CompareDoubles1是否更快取决于您的机器和魔术常数的选择。只是测量它。您需要确保提供匹配的魔术常量,否则您将检查与不同信任区域的相等性,从而产生不同的结果。

答案 2 :(得分:1)

我认为将差异与固定容差进行比较是一个坏主意。

如果您将容差设置为1e-6,那么会发生什么,但是您比较的两个数字是 1.11e-9和1.19e-9?

这些被认为是相同的,即使它们在第二个有效数字之后不同。这可能不是你想要的。

我认为进行比较的更好方法是

equal = ( fabs(A - B) <= tol*max(fabs(A), fabs(B)) )

注意,&lt; =(而不是&lt;),因为上述内容也必须适用于0 == 0。如果设置tol = 1e-14,当它们等于14位有效数字时,两个数字将被视为相等。

旁注:如果你想测试一个数字是否为零,那么上面的测试可能并不理想,那么确实应该使用绝对阈值。

答案 3 :(得分:0)

如果您的示例中使用的舍入函数意味着舍入到第4个十进制数字,则这根本不正确。例如,如果A和B是0.000003和0.000004,它们将四舍五入为0.0,因此将被比较为相等。

通用的compairison函数不能与常量tolarance一起使用,而是与相对的一起使用。但是你在引用问题的帖子中都解释了这一点。

答案 4 :(得分:0)

没有'正确'的方法来比较浮点值(即使f == 0.0可能是正确的)。不同的比较可能是合适的。看看http://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/

答案 5 :(得分:0)

与其他帖子类似,但引入了比例不变性:如果你正在做一些事情,比如将两组数字加在一起,然后你想知道两个集合的数量是否相等,你可以得到日志的绝对值 - 比率(对数差)和测试,看它是否小于你的规定公差。这样,例如如果在求和计算中将所有数字乘以10或100,则不会影响答案是否相等的结果。您应该有一个单独的测试来确定两个数字是否相等,因为它们足够接近0。