如何比较双精度浮点数?

3
我知道当我想检查double == double时,应该这样写:

if(Math.abs(double1 - double2) < 0.000001)

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

但是如果我想检查 a > b 或者 b > a 该怎么办?


1
但是如果我想检查 a > b 还是 b > a 呢?那么你可以使用 a > bb > a - user529758
改为 >= EPSILON - Rick James
为什么不是 a == b? - Ted
2个回答

11

对于包含先前操作误差的浮点数,没有通用解决方案可供比较。必须使用特定于应用程序的代码。因此,要得到正确的答案,您必须更具体地描述您的情况。例如,如果您正在对列表或其他数据结构中的数字进行排序,则不应使用任何容忍度进行比较。

通常,如果您的程序需要比较两个数字的顺序,但由于仅具有这些数字的近似值而无法进行比较,则应重新设计程序而不是尝试允许数字错误排序。

潜在问题是使用不正确的数据进行正确计算通常是不可能的。如果您想要计算两个精确数学值 xy 的某个函数,但您唯一拥有的数据是一些错误计算的值 xy,通常无法计算出完全正确的结果。例如,假设您想知道和 x+y 是多少,但您只知道 x 是 3,y 是 4,但您不知道真正的、精确的 xy 是什么。那么你不能计算 x+y

如果您知道 xy 大约是 近似xy,则可以通过添加 xy 来计算出 x+y 的近似值。当被计算的函数具有合理的导数时,这种方法是有效的:稍微改变具有合理导数的函数的输入会轻微改变其输出结果。但当您想要计算的函数具有不连续性或大导数时,此方法将失败。例如,如果您要使用近似值 x 计算平方根 x(在实域中),但由于先前的舍入误差,x 可能为负,则计算 sqrt(x) 可能会产生异常。同样,比较不等式或顺序是一种不连续函数:输入的轻微变化可能完全改变答案。

常见的坏建议是使用“公差”进行比较。这种方法为假阴性(如果真实的数学值进行比较,会错误地拒绝满足比较的数字)换取了假阳性(会错误地接受不满足比较的数字)。

一个应用程序是否可以容忍假接受取决于该应用程序。因此,没有通用的解决方案。

要设置的公差级别,甚至计算公差的方式,取决于数据、错误和之前的计算。因此,即使使用公差进行比较是可接受的,在应用时要使用多少公差以及如何计算它都取决于应用程序。没有通用的解决方案。


1
+1 三次重复“没有通用解决方案” :-)没有通用解决方案,以下是一些可能的解决方案。请根据您的具体情况选择最适合您的解决方案。 - Mark Dickinson

2

类比比较如下:

a > b - EPSILON

并且

b > a - EPSILON

我假设EPSILON是一个很小的正数。

抱歉打错了,我的意思是“如何解决这个问题超越加号?” - herohuyongtao
3
ab完全相等时,这个比较不会出错吗?即使a不大于bfloat a = 1; float b = a; (a > b - EPSILON)也会等于true - user694733
但是在那种情况下,使用epsilon方法有什么意义,而不是简单地使用(a >= b)吗? - user694733
@DavidHeffernan 但是如果两个数字相等,您不希望其中一个数字比另一个数字大,对吗? - user529758
==的情况下我理解,但是>=的本质不同。它匹配某个点之前的所有值。在我看来,使用大于/小于-运算符的epsilon只会引入错误(正如我的第一个例子所示)。 - user694733
显示剩余6条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接