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

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

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

比如:

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

似乎是浪费加工。

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


当前回答

不幸的是,即使您的“浪费”代码也是不正确的。EPSILON是可以添加到1.0并更改其值的最小值。值1.0非常重要——更大的数字在添加到EPSILON时不会改变。现在,您可以将这个值缩放到您正在比较的数字,以判断它们是否不同。比较两个双精度对象的正确表达式是:

if (fabs(a - b) <= DBL_EPSILON * fmax(fabs(a), fabs(b)))
{
    // ...
}

这是最小值。一般来说,你会想要在计算中考虑噪声,并忽略一些最不重要的位,所以更现实的比较应该是这样的:

if (fabs(a - b) <= 16 * DBL_EPSILON * fmax(fabs(a), fabs(b)))
{
    // ...
}

如果比较性能对您非常重要,并且您知道值的范围,那么您应该使用定点数字。

其他回答

与epsilon值进行比较是大多数人所做的(甚至是在游戏编程中)。

你应该稍微改变你的实现:

bool AreSame(double a, double b)
{
    return fabs(a - b) < EPSILON;
}

编辑:克里斯特在最近的一篇博客文章中添加了一堆关于这个主题的很棒的信息。享受。

这取决于你想要的比较有多精确。如果您想对完全相同的数字进行比较,那么只需使用==。(除非你真的想要完全相同的数字,否则你几乎不会想这么做。)在任何一个不错的平台上,你都可以做到以下几点:

diff= a - b; return fabs(diff)<EPSILON;

因为晶圆厂往往很快。我说的快是指它基本上是一个位与,所以它最好快。

用于比较双精度和浮点数的整数技巧很好,但往往会使各种CPU管道更难有效处理。现在,由于使用堆栈作为频繁使用的值的临时存储区域,在某些有序架构上它肯定不会更快。(在乎的人可以去Load-hit-store。)

你写的代码有bug:

return (diff < EPSILON) && (-diff > EPSILON);

正确的代码应该是:

return (diff < EPSILON) && (diff > -EPSILON);

(…是的,这是不同的)

我想知道晶圆厂是否会让你在某些情况下失去懒惰的评价。我会说这取决于编译器。你可能想两种都试试。如果它们在平均水平上是相等的,则采用晶圆厂实现。

如果你有一些关于两个浮点数中哪一个比另一个更大的信息,你可以根据比较的顺序来更好地利用惰性求值。

最后,通过内联这个函数可能会得到更好的结果。不过不太可能有太大改善……

编辑:OJ,谢谢你纠正你的代码。我相应地删除了我的评论

在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();
}

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

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

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