11

这是对浮点值相等性测试的后续内容:“精度”常量是否有标准名称?.
对于相等,有一个非常相似的问题Double.Epsilon,大于、小于、小于或等于、大于或等于


众所周知,两个浮点值xy的相等性测试应该看起来更像这样(而不是简单的 =):

abs( x - y ) < epsilon   ,其中epsilon是一个非常小的值。

如何选择epsilon的值?

显然,最好为epsilon选择一个尽可能小的值,以便为相等性检查获得尽可能高的精度。

例如,.NET 框架提供了一个常数System.Double.Epsilon(= 4.94066 × 10 -324System.Double ),它表示大于零的最小正值。

但是,事实证明,这个特定值不能可靠地用作epsilon,因为:

0+ System.Double.Epsilon≠  0

1 + System.Double.Epsilon= 1 (!)

也就是说,如果我理解正确,因为该常数小于machine epsilon

→ 这是正确的吗?

→ 这是否也意味着我可以可靠地使用epsilon := machine epsilon进行相等测试?

删除了这两个问题,因为上面链接的第二个 SO 问题已经充分回答了它们。


链接到维基百科的文章说,对于 64 位浮点数(即double许多语言中的类型),机器 epsilon 等于:

2 -53或大约。0.000000000000000111(小数点后有 15 个零的数字)

→ 是否由此得出所有 64 位浮点值都保证精确到 14 位(如果不是 15 位)?

4

4 回答 4

11

如何为 epsilon 选择一个值?

简短回答:您选择适合您的应用程序需求的小值。

长答案:没有人可以知道您的应用程序进行了哪些计算以及您期望结果有多准确。由于舍入误差总和机器 epsilon 几乎总是太大,因此您必须选择自己的值。根据您的需要,0.01 就足够了,或者可能 0.00000000000001 或更少。

问题是,您真的想要/需要对浮点值进行相等测试吗?也许你应该重新设计你的算法。

于 2010-07-19T13:21:49.570 回答
5

过去,当我不得不使用 epsilon 值时,它比机器 epsilon 值大得多。

尽管它是针对 32 位双精度数(而不是 64 位双精度数),但我们发现在我们的特定应用程序中,大多数(如果不是全部)计算值都需要10 -6的 epsilon 值。

您选择的 epsilon 值取决于您的数字的规模。如果您正在处理非常大的数据(例如 10 +10),那么您可能需要更大的 epsilon 值,因为您的有效数字不会延伸到小数部分(如果有的话)。如果您正在处理非常小的(例如 10 -10),那么显然您需要一个小于此值的 epsilon 值。

您需要进行一些实验,执行计算并检查输出值之间的差异。只有当您知道潜在答案的范围时,您才能决定适合您的应用的值。

于 2010-07-19T13:20:10.577 回答
5

可悲的事实是:浮点比较没有合适的 epsilon。如果您不想遇到严重的错误,请使用另一种方法进行浮点相等测试。

近似浮点比较是一个非常棘手的领域,该abs(x - y) < eps方法仅适用于非常有限的值范围,主要是因为绝对差异没有考虑比较值的大小,还因为发生了显着数字消除在具有不同指数的两个浮点值的减法中。

有更好的方法,使用相对差异或 ULP,但它们有自己的缺点和陷阱。阅读 Bruce Dawson 的优秀文章Comparing Floating Point Numbers,2012 版,了解浮点比较到底有多棘手——恕我直言,任何进行浮点编程的人都必须阅读!我敢肯定,由于幼稚的浮点比较,已经花费了无数人年的时间来找出细微的错误。

于 2015-02-26T19:42:23.457 回答
3

我也对正确的程序有疑问。但是我认为应该这样做:

abs(x - y) <= 0.5 * eps * max(abs(x), abs(y))

代替:

abs(x - y) < eps

其原因来自机器 epsilon 的定义。使用python代码:

import numpy as np
real = np.float64
eps = np.finfo(real).eps

## Let's get the machine epsilon
x, dx = real(1), real(1)
while x+dx != x: dx/= real(2) ;

print "eps = %e  dx = %e  eps*x/2 = %e" % (eps, dx, eps*x/real(2))

这使:eps = 2.220446e-16 dx = 1.110223e-16 eps*x/2 = 1.110223e-16

## Now for x=16
x, dx = real(16), real(1)
while x+dx != x: dx/= real(2) ;

print "eps = %e  dx = %e  eps*x/2 = %e" % (eps, dx, eps*x/real(2))

现在给出:eps = 2.220446e-16 dx = 1.776357e-15 eps*x/2 = 1.776357e-15

## For x not equal to 2**n
x, dx = real(36), real(1)
while x+dx != x: dx/= real(2) ;

print "eps = %e  dx = %e  eps*x/2 = %e" % (eps, dx, eps*x/real(2))

返回:eps = 2.220446e-16 dx = 3.552714e-15 eps*x/2 = 3.996803e-15

然而,尽管 dx 和 eps*x/2 之间存在差异,但我们看到dx <= eps*x/2,因此它用于等式测试、在测试数值过程中的收敛性时检查容差等。

这类似于: www.ibiblio.org/pub/languages/fortran/ch1-8.html#02中的内容,但是如果有人知道更好的程序或者这里的某些内容不正确,请说。

于 2014-01-23T13:31:43.070 回答