Mic*_*bon 17 floating-point floating-accuracy epsilon
为了简化问题,我想说我想a / (b - c)在floats 上计算表达式.
为了确保结果是有意义的,我可以检查b和c是相等的:
float EPS = std::numeric_limits<float>::epsilon();
if ((b - c) > EPS || (c - b) > EPS)
{
return a / (b - c);
}
Run Code Online (Sandbox Code Playgroud)
但是我的测试表明,如果可能的话,不能保证有意义的结果,也不能不提供结果.
a = 1.0f;
b = 0.00000003f;
c = 0.00000002f;
Run Code Online (Sandbox Code Playgroud)
结果:不满足if条件,但表达式将生成正确的结果100000008(与浮点数的精度相同).
a = 1e33f;
b = 0.000003;
c = 0.000002;
Run Code Online (Sandbox Code Playgroud)
结果:满足if条件,但表达式不会产生有意义的结果+1.#INF00.
我发现检查结果更可靠,而不是参数:
const float INF = numeric_limits<float>::infinity();
float x = a / (b - c);
if (-INF < x && x < INF)
{
return x;
}
Run Code Online (Sandbox Code Playgroud)
但是那时的epsilon是什么呢?为什么每个人都说epsilon很好用?
Pas*_*uoq 19
"处理浮点数时必须使用epsilon"是程序员对浮点计算的表面理解的一种下意识反应,一般用于比较(不仅仅是零).
这通常是无益的,因为它没有告诉你如何最小化舍入错误的传播,它没有告诉你如何避免取消或吸收问题,甚至当你的问题确实与两个浮点数的比较有关时,它并没有告诉你epsilon对你正在做的事情有什么价值.
如果你还没有读过每个计算机科学家应该知道的关于浮点算术的内容,那么这是一个很好的起点.除此之外,如果您对示例中除法结果的精度感兴趣,则必须估计先前舍入误差的不精确b-c程度,因为实际上如果小,则绝对误差小对应于大的绝对误差在结果上.如果你的担心只是分裂不应该溢出,那么你的测试(在结果上)是正确的.没有理由测试带有浮点数的空除数,你只需要测试结果的溢出,它会捕获除数为空的情况和除数非常小以致结果无法表示的情况.任何精度.b-c
关于舍入误差的传播,存在可以帮助您估计它的专用分析器,因为手动操作是一件单调乏味的事情.