首页 文章

机器epsilon的使用是否适合浮点相等测试?

提问于
浏览
10

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


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

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

How to choose a value for epsilon?

显然最好选择epsilon作为尽可能小的值,以获得相等检查的最高精度 .

例如,.NET框架提供了一个常量 System.Double.Epsilon (= 4.94066×10-324),它表示大于零的最小正 System.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个零的数字)

→ Does it follow from this that all 64-bit floating point values are guaranteed to be accurate to 14 (if not 15) digits?

4 回答

  • 9

    如何选择epsilon的值?

    Short Answer: 您需要一个适合您应用需求的小值 .

    Long Answer: 没有人能够知道您的应用程序执行了哪些计算以及您希望结果如何 accurate . 由于舍入错误总结机器epsilon几乎所有时间都太大,所以你必须选择自己的值 . 根据您的需要,0.01是足够的,或者可能是0.00000000000001或更少 .

    问题是, do you really want/need to do equality tests on floating point values ?也许你应该重新设计你的算法 .

  • 3

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

    虽然它是32位双精度(而不是64位双精度),但我们发现 our particular application 中的大多数(如果不是全部)计算值需要10-6的epsilon值 .

    您选择的epsilon值取决于您的数字的比例 . 如果您正在处理 very large (10 10说)那么您可能需要更大的epsilon值,因为您的有效数字不会延伸到小数部分(如果有的话) . 如果你正在处理 very small (10-10说)那么显然你需要一个比这个小的epsilon值 .

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

  • 5

    可悲的事实是: There is no appropriate epsilon for floating-point comparisons. 如果你不想遇到严重的错误,请使用另一种方法进行浮点相等测试 .

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

    有更好的方法,使用相对差异或ULP,但它们有自己的缺点和陷阱 . 阅读Bruce Dawson的优秀文章Comparing Floating Point Numbers, 2012 Edition,了解如何进行棘手的浮点比较 - 对于任何进行浮点编程的人都必须阅读恕我直言!我敢肯定,由于天真的浮点比较,我花了数千年的时间来寻找细微的错误 .

  • 2

    关于什么是正确的程序,我也有疑问 . 不过我认为应该这样做:

    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,但是如果有人知道更好的程序或者这里的东西是不正确的,请说 .

相关问题