比较两个双精度浮点数或两个浮点数最有效的方法是什么?

简单地这样做是不正确的:

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

比如:

bool CompareDoubles2 (double A, double B) 
{
   diff = A - B;
   return (diff < EPSILON) && (-diff < EPSILON);
}

似乎是浪费加工。

有人知道更聪明的浮点比较器吗?


当前回答

意识到这是一个老话题,但这篇文章是我发现的关于比较浮点数的最直接的文章之一,如果你想探索更多,它也有更详细的参考资料,它的主要站点涵盖了处理浮点数的完整范围的问题《浮点指南:比较》。

我们可以在浮点公差中找到一篇更实用的文章,并指出有绝对公差测试,在c++中归结为:

bool absoluteToleranceCompare(double x, double y)
{
    return std::fabs(x - y) <= std::numeric_limits<double>::epsilon() ;
}

及相对耐量试验:

bool relativeToleranceCompare(double x, double y)
{
    double maxXY = std::max( std::fabs(x) , std::fabs(y) ) ;
    return std::fabs(x - y) <= std::numeric_limits<double>::epsilon()*maxXY ;
}

文章指出,当x和y较大时,绝对检验失败;当x和y较小时,相对检验失败。假设绝对耐受性和相对耐受性是相同的,综合测试将是这样的:

bool combinedToleranceCompare(double x, double y)
{
    double maxXYOne = std::max( { 1.0, std::fabs(x) , std::fabs(y) } ) ;

    return std::fabs(x - y) <= std::numeric_limits<double>::epsilon()*maxXYOne ;
}

其他回答

在数值软件中,确实有这样的情况,你需要检查两个浮点数是否完全相等。我就一个类似的问题发表了这篇文章

https://stackoverflow.com/a/10973098/1447411

所以你不能说“CompareDoubles1”是错误的。

我对任何涉及浮点减法的答案都非常谨慎(例如,fabs(a-b) < epsilon)。首先,浮点数在更大的量级上变得更稀疏,在足够大的量级上,当间隔大于时,您可能只需要做a == b。其次,减去两个非常接近的浮点数(因为您正在寻找接近相等的浮点数)正是您得到灾难性抵消的方式。

虽然不能移植,但我认为grom的答案在避免这些问题方面做得最好。

在c++中获取的可移植方法是

#include <limits>
std::numeric_limits<double>::epsilon()

然后比较函数变成

#include <cmath>
#include <limits>

bool AreSame(double a, double b) {
    return std::fabs(a - b) < std::numeric_limits<double>::epsilon();
}

我使用这个代码:

bool AlmostEqual(double v1, double v2)
    {
        return (std::fabs(v1 - v2) < std::fabs(std::min(v1, v2)) * std::numeric_limits<double>::epsilon());
    }

你不能用一个固定的。根据double的值,EPSILON会发生变化。

更好的双比较应该是:

bool same(double a, double b)
{
  return std::nextafter(a, std::numeric_limits<double>::lowest()) <= b
    && std::nextafter(a, std::numeric_limits<double>::max()) >= b;
}