Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/amazon-web-services/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Floating point 是不是;“ε”;在浮点计算中真的能保证什么吗?_Floating Point_Floating Accuracy_Epsilon - Fatal编程技术网

Floating point 是不是;“ε”;在浮点计算中真的能保证什么吗?

Floating point 是不是;“ε”;在浮点计算中真的能保证什么吗?,floating-point,floating-accuracy,epsilon,Floating Point,Floating Accuracy,Epsilon,为了简化问题,假设我想计算floats上的表达式a/(b-c) 为了确保结果有意义,我可以检查b和c是否相等: float EPS=std::numeric_limits::epsilon(); 如果((b-c)>EPS | |(c-b)>EPS) { 返回a/(b-c); } 但我的测试表明,这既不足以保证有意义的结果,也不足以在可能的情况下提供结果 案例1: a=1.0f; b=0.00000003f; c=0.00000002f; 结果:如果不满足条件,则表达式将生成正确的结果1000

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

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

float EPS=std::numeric_limits::epsilon();
如果((b-c)>EPS | |(c-b)>EPS)
{
返回a/(b-c);
}
但我的测试表明,这既不足以保证有意义的结果,也不足以在可能的情况下提供结果

案例1:
a=1.0f;
b=0.00000003f;
c=0.00000002f;
结果:如果不满足条件,则表达式将生成正确的结果10000008(与浮点精度一样)

案例2:
a=1e33f;
b=0.000003;
c=0.000002;
结果:满足if条件,但表达式不会产生有意义的结果
+1.#INF00

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

const float INF=numeric_limits::infinity();
浮动x=a/(b-c);
if(-INF

但是epsilon是干什么的?为什么每个人都说epsilon很好用?

epsilon用于确定两个受舍入误差影响的数字是否足够接近,可以认为是“相等的”。请注意,测试
fabs(b/c-1)
fabs(b-c)
更好,而且由于IEEE浮点数的设计,测试
abs(*(int*)和b-*(int*)&c)
(其中EPSI是一些小整数)

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

“处理浮点运算时必须使用ε”是程序员的下意识反应,他们对浮点计算有着肤浅的理解,通常用于比较(而不仅仅是零)


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

如果你没有读过,这是一个很好的起点。除此之外,如果您对示例中除法结果的精度感兴趣,您必须估计先前的舍入误差造成的
b-c
的不精确程度,因为如果
b-c
很小,则较小的绝对误差对应于结果的较大绝对误差。如果您只关心除法不应溢出,那么您的测试(对结果)是正确的。没有理由用浮点数来测试空除数,只需测试结果是否溢出,这将捕获除数为空以及除数太小以致无法以任何精度表示结果的情况


关于舍入误差的传播,有一些方法可以帮助您估计舍入误差,因为手工操作是一件乏味的事情。

对于您的
*(int*)和
构造,“严格别名规则”人群会有一些意见。我个人不同意编译器的态度,他们强调基准测试时间,而不是现有的实践和程序员对语言含义的广泛理解,但他们有一点:你的代码会被现代编译器弄错。谢谢你的评论,帕斯卡。我可以将其全部封装在一个联合体中,但对于这样一个切点来说,这将有点过于冗长。小心
*(int*)和
技巧:除了Pascal提到的类型双关问题外,它在0附近也不起作用:如果b和c非常接近,但有相反的符号(例如b=2e-45f,c=-0.0f),那么你的测试将失败。Mark:是的,有一些边缘案例,但你的不在其中。由于符号位的原因,正数和负数相距数英里(零与零之间以及与非零之间的距离也是如此)。我相信去噪是一个真正的边缘情况。啊,现在我明白了。您希望这两个数字几乎相等。这实际上取决于你是从算术还是几何的角度考虑相似性。对于算术相似性,你是完全正确的,但ulp度量仅适用于几何相似性,在这种情况下,你的两个数字处于完全不同的宇宙中,出于所有目的和目的。“它不会告诉你epsilon的什么值适合你所做的事”:请进一步强调这句话,这真的很重要。没有理由用浮点数来测试空除数,只需测试结果是否溢出即可。浮点除以零导致C和C++中的未定义行为。@ MaxBarraclough C标准不指定具有无穷或NANN的浮点系统,所以当然在C标准浮点除以0是UB。根据C17 6.5:5,浮点溢出在该最小设置中也是UB。同样地,也没有必要单独地用零除法。现在,常识表明,当C编译器记录它实现IEEE 754 for
float
double
时,溢出操作根据IEEE 754的规则生成inf/NaN,IEEE 754的规则也适用于零除。这就是“实现IEEE 754”的意思。@MaxBarraclough编译器不能声称实现IEEE 754而离开
0./0。
UB。词语有意义。