比较两个double
或两个float
值的最有效方法是什么?
简单地这样做是不正确的:
bool CompareDoubles1 (double A, double B)
{
return A == B;
}
但是类似:
bool CompareDoubles2 (double A, double B)
{
diff = A - B;
return (diff < EPSILON) && (-diff < EPSILON);
}
似乎是废物处理。
有人知道更聪明的浮点比较器吗?
#1楼
实际上,在数字软件中,您需要检查两个浮点数是否完全相等。 我在类似的问题上发布了
https://stackoverflow.com/a/10973098/1447411
因此,您不能说“ CompareDoubles1”通常是错误的。
#2楼
意识到这是一个古老的话题,但是本文是我发现的比较浮点数最直接的文章之一,如果您想探索更多,它也提供了更详细的参考,并且主要站点涵盖了所有问题处理浮点数《浮点指南:比较》 。
我们可以在“ 浮点公差 ”中找到一些更实用的文章,并注意到存在绝对公差测试,在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
较大时,绝对测试将失败,而当它们相对较小时,则相对测试将失败。 假设他的绝对公差和相对公差相同,那么组合测试将如下所示:
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 ;
}
#3楼
与大多数人所做的事情(包括在游戏编程中)相比,与ε值进行比较。
您应该对实现进行一些更改:
bool AreSame(double a, double b)
{
return fabs(a - b) < EPSILON;
}
编辑:克里斯特(Christer)在最近的博客文章中添加了有关此主题的大量信息。 请享用。
#4楼
您编写的代码存在错误:
return (diff < EPSILON) && (-diff > EPSILON);
正确的代码是:
return (diff < EPSILON) && (diff > -EPSILON);
(...是的,这是不同的)
我不知道晶圆厂在某些情况下是否不会让您失去懒惰的评估。 我会说这取决于编译器。 您可能要同时尝试两者。 如果它们平均相等,则采用fab实施。
如果您有关于两个浮点数中哪个比另一个浮点数更大的信息,则可以按比较的顺序进行操作,以更好地利用延迟评估。
最后,通过内联此函数可能会获得更好的结果。 虽然不太可能改善...
编辑:OJ,感谢您更正您的代码。 我因此删除了我的评论
#5楼
有关更深入的方法,请阅读比较浮点数 。 这是该链接的代码片段:
// Usable AlmostEqual function
bool AlmostEqual2sComplement(float A, float B, int maxUlps)
{
// Make sure maxUlps is non-negative and small enough that the
// default NAN won't compare as equal to anything.
assert(maxUlps > 0 && maxUlps < 4 * 1024 * 1024);
int aInt = *(int*)&A;
// Make aInt lexicographically ordered as a twos-complement int
if (aInt < 0)
aInt = 0x80000000 - aInt;
// Make bInt lexicographically ordered as a twos-complement int
int bInt = *(int*)&B;
if (bInt < 0)
bInt = 0x80000000 - bInt;
int intDiff = abs(aInt - bInt);
if (intDiff <= maxUlps)
return true;
return false;
}
来源:oschina
链接:https://my.oschina.net/stackoom/blog/3159215