代码之家  ›  专栏  ›  技术社区  ›  stakx - no longer contributing Saravana Kumar

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

  •  10
  • stakx - no longer contributing Saravana Kumar  · 技术社区  · 14 年前

    这是一个后续行动 Testing for floating-point value equality: Is there a standard name for the “precision” constant?
    有一个非常相似的问题 Double.Epsilon for equality, greater than, less than, less than or equal to, greater than or equal to .


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

    防抱死制动系统( y )< ,在哪里 ε

    如何为选择值 ?

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

    System.Double.Epsilon (=4.94066 × 10 -324 System.Double 大于零的值。

    然而,事实证明,这个特定的值不能可靠地用作 ε

    0 + 0

    1 + 系统.Double.Epsilon = 1 (!)

    如果我理解正确的话,因为常数小于 machine epsilon .

    → 是这样吗?

    ε:=机器ε 为了平等测试?


    链接到维基百科的文章说,对于64位浮点数(即 double

    2 ,或约0.000000000000000111(小数点后有15个零的数字)

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

    4 回复  |  直到 7 年前
        1
  •  11
  •   codymanix    14 年前

    如何选择epsilon的值?

    简短回答: 你可以取一个适合你的应用需求的小值。

    没有人知道你的应用程序做了哪些计算以及如何计算 你希望你的结果是正确的。由于舍入误差和机器epsilon几乎总是太大,所以您必须选择自己的值。根据您的需要,0.01就足够了,或者0.00000000000001或更小。

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

        2
  •  5
  •   ChrisF    14 年前

    在过去,当我不得不使用一个epsilon值时,它比机器的epsilon值要大得多。

    -6 中大多数(如果不是全部)计算值都需要 我们的特殊应用 .

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

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

        3
  •  5
  •   Franz D.    10 年前

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

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

    有更好的方法,使用相对差异或ULP,但它们有自己的缺点和缺陷。读布鲁斯道森的优秀文章 Comparing Floating Point Numbers, 2012 Edition

        4
  •  2
  •   cvr    11 年前

    我也有关于什么是正确的程序的问题。不过,我认为应该:

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

    而不是:

    abs(x - y) < eps
    

    原因来自于机器ε的定义。使用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 , 但是,如果有人知道更好的程序或如果这里有什么不正确的,请说。

    推荐文章