“ Epsilon”是否确实保证了浮点计算中的任何内容?
-
02-10-2019 - |
题
为了使问题简短,假设我想计算表达式 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);
}
但是我的测试表明,如果可能的话,这还不足以保证有意义的结果,也不能否提供结果。
情况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) < EPS
比 fabs(b-c) < EPS
, ,甚至更好 - 多亏了IEEE Floats的设计 - 测试 abs(*(int*)&b - *(int*)&c) < EPSI
(EPSI是一些小整数)。
您的问题具有不同的性质,可能需要测试结果而不是输入。