关于DB中的DBL_EPSILON和Machine-Epsilon的困惑

时间:2014-07-05 07:34:54

标签: c floating-point

Machine-Epsilon似乎有两个定义:

  1. 将实数四舍五入为下一个浮点数时的最大相对误差。
  2. 1.0 + machine_eps!= 1.0
  3. 的最小正数

    首先,我没有看到这两者如何相关。 在我的理解中,第二个DBL_EPSILON不符合定义2:

    以下程序打印:

    DBL_EPSILON:            2.220446049250313080847e-16
    DBL_EPSILON / 2:        1.110223024625156540424e-16
    1.0 + DBL_EPSILON:      1.000000000000000222045e+00
    1.0 + DBL_EPSILON / 2:  1.000000000000000000000e+00
    
    m_eps                   2.220446049250313080847e-16
    m_eps -1u               2.220446049250312834328e-16
    
    1.0 + m_eps -1u         1.000000000000000222045e+00
    
    (m_eps -1u < DBL_EPSILON):     True
    (m_eps -1u == DBL_EPSILON/2):  False
    

    m_eps -1u应该是一个较小的数字但非常接近DBL_EPSILON。同 定义2)应该1.0 + m_eps -1u不评估为1.0?为什么有必要 为此将DBL_EPSILON除以2?

    #include <stdout.h>
    #include <stdint.h>
    #inlcude <float.h>
    
    union Double_t {
        double f;
        int64_t i;
    };
    
    int main(int argc, char *argv[])
    {
        union Double_t m_eps;
    
        printf("DBL_EPSILON: \t\t%.*e\n", DECIMAL_DIG, DBL_EPSILON);
        printf("DBL_EPSILON / 2: \t%.*e\n", DECIMAL_DIG, DBL_EPSILON / 2);
    
        printf("1.0 + DBL_EPSILON: \t%.*e\n", DECIMAL_DIG, 1.0 + DBL_EPSILON);
        printf("1.0 + DBL_EPSILON / 2: \t%.*e\n", DECIMAL_DIG, 1.0 + DBL_EPSILON / 2);
    
        m_eps.f = DBL_EPSILON;
        printf("\nm_eps \t\t\t%.*e\n", DECIMAL_DIG, m_eps.f);
    
        m_eps.i -= 1;
        printf("m_eps -1u\t\t%.*e\n", DECIMAL_DIG, m_eps.f);
        printf("\n1.0 + (m_eps -1u)\t\t%.*e\n", DECIMAL_DIG, 1.0 + m_eps.f);
    
        printf("\n(m_eps -1u < DBL_EPSILON): %s\n",
                (m_eps.f < DBL_EPSILON) ? "True": "False"
                );
    
        printf("(m_eps -1u == DBL_EPSILON/2): %s\n",
                (DBL_EPSILON/2 == m_eps.f) ? "True": "False"
                );
        return 0;
    }
    

1 个答案:

答案 0 :(得分:8)

DBL_EPSILON的错误定义,你引用的那个“最小正数,1.0 + machine_eps!= 1”,正在浮动。您甚至可以在标准库中找到它,也可以在StackOverflow上以其他方式找到答案。当在标准库中找到它时,它在一个值附近的注释中显然与注释不对应,但对应于正确的定义:

  

DBL_EPSILON:这是1和最小值之间的差异   类型double的浮点数大于1.(从GNU C库中获取正确的定义)

C99标准用这种方式表达:

  

在给定浮点类型中可表示的1和最小值之间的差值,b ^(1-p)

这可能是您混淆的原因。忘记错误的定义。我写了一篇关于这个here的咆哮(这非常像你的问题)。


您的问题中的另一个定义“将实数舍入到下一个浮点数时的最大相对误差”是正确的 - 当舍入的结果是正常的浮点数时。将实数舍入到有限浮点数会产生实数值的1/2 ULP内的浮点数。对于正常的浮点数,此1/2 ULP绝对错误转换为DBL_EPSILON / 2和DBL_EPSILON / 4之间的相对错误,具体取决于浮点数在binade中的位置。