为了使问题简短,假设我想计算表达式 a / (b - c)floats。

为了确保结果有意义,我可以检查是否 bc 相等:

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

但是我的测试表明,如果可能的话,这还不足以保证有意义的结果,也不能否提供结果。

情况1:

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

结果: 如果不满足条件,则表达式将产生正确的结果100000008(如浮子的精度)。

案例2:

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

结果: 如果满足条件,则表达式并没有产生有意义的结果 +1.#INF00.

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

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

但是,那是伊普西隆的目的,为什么每个人都说Epsilon很好地使用呢?

有帮助吗?

解决方案

“在处理浮子时必须使用epsilon”是对程序员的膝盖反应,对浮点计算具有表面的理解,以进行比较(不仅为零)。

这通常是无济于事的,因为它不会告诉您如何最大程度地减少四舍五入错误的传播,它不会告诉您如何避免取消或吸收问题,即使您的问题确实与两个浮标的比较有关, 它不会告诉您Epsilon的价值适合您正在做什么.

如果您没有阅读 每个计算机科学家对浮点算术都应了解什么, ,这是一个很好的起点。除此之外,如果您对示例中该部门结果的精确性感兴趣,则必须估计 b-c 是由 以前的 四舍五入错误,因为确实 b-c 很小,一个小的绝对误差对应于结果上的绝对误差。如果您的担心仅是该部门不应溢出,那么您的测试(在结果上)是正确的。没有理由测试带有浮点数的无效除数,您只需测试结果的溢出,这两个情况都可以捕获除数为null和除数的情况。任何精度。

关于舍入错误的传播,存在 专业分析仪 这可以帮助您估计它,因为这是一件乏味的事情。

其他提示

Epsilon用于确定是否有两个数字受到舍入误差的距离足够接近,以至于被视为“相等”。请注意,最好测试 fabs(b/c - 1) < EPSfabs(b-c) < EPS, ,甚至更好 - 多亏了IEEE Floats的设计 - 测试 abs(*(int*)&b - *(int*)&c) < EPSI (EPSI是一些小整数)。

您的问题具有不同的性质,可能需要测试结果而不是输入。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top