代码之家  ›  专栏  ›  技术社区  ›  Michal Czardybon

“epsilon”真的能保证浮点计算吗?

  •  16
  • Michal Czardybon  · 技术社区  · 16 年前

    为了简化问题,假设我要计算表达式 a / (b - c) float s。

    为了确保结果有意义,我可以检查 b c 等于:

    float EPS = std::numeric_limits<float>::epsilon();
    if ((b - c) > EPS || (c - b) > EPS)
    {
        return a / (b - c);
    }
    

    但我的测试表明,这既不足以保证有意义的结果,也不足以在可能的情况下提供一个结果。

    a = 1.0f;
    b = 0.00000003f;
    c = 0.00000002f;
    

    结果: if条件不满足,但表达式将生成正确的结果10000008(关于浮点精度)。

    a = 1e33f;
    b = 0.000003;
    c = 0.000002;
    

    结果: if条件满足,但表达式不会产生有意义的结果 +1.#INF00 .

    我发现检查结果更可靠,而不是参数:

    const float INF = numeric_limits<float>::infinity();
    float x = a / (b - c);
    if (-INF < x && x < INF)
    {
         return x;
    }
    

    但是为什么每个人都说epsilon好用呢?

    2 回复  |  直到 6 年前
        1
  •  21
  •   Pascal Cuoq    9 年前

    “在处理浮点运算时必须使用epsilon”是程序员对浮点计算的肤浅理解的下意识反应,通常用于比较(不仅仅是到零)。

    这通常是没有帮助的,因为它没有告诉你如何最小化舍入误差的传播,它没有告诉你如何避免抵消或吸收问题,甚至当你的问题确实与两个浮点值的比较有关时,

    如果你没有读过 What Every Computer Scientist Should Know About Floating-Point Arithmetic ,这是一个很好的起点。除此之外,如果您对示例中除法结果的精度感兴趣,则必须估计其不精确程度 b-c 是由 以前的 b-c级 是小的,一个小的绝对误差对应一个大的绝对误差的结果。如果你只关心除法不能溢出,那么你的测试(对结果)是对的。没有理由用浮点数来测试空除数,只需测试结果是否溢出,这会捕获除数为空和除数太小以致无法用任何精度表示结果的情况。

    关于舍入误差的传播,存在 specialized analyzers 这可以帮助你估计它,因为这是一个乏味的事情做手工。

        2
  •  3
  •   Marcelo Cantos    16 年前

    Epsilon用于确定两个受舍入误差影响的数字是否足够接近而被认为是“相等的”。请注意,最好进行测试 fabs(b/c - 1) < EPS 比 fabs(b-c) < EPS abs(*(int*)&b - *(int*)&c) < EPSI (其中EPSI是一些小整数)。

    推荐文章