在C ++中进行数学运算时,浮点误差如何传播?

时间:2014-09-06 21:04:27

标签: c++ c floating-point floating-accuracy floating-point-precision

让我们说我们宣布了以下变量

float a = 1.2291;

float b = 3.99;

float变量具有精度6,(如果我理解正确的话)意味着计算机实际存储的数量与您想要的实际数量之间的差异将小于10^-6

这意味着ab都有一些小于10^-6的错误

因此,计算机内部a实际上可能是1.229100000012123b可能是3.9900000191919

现在让我们说你有以下代码

float c = 0;
for(int i = 0; i < 1000; i++)
      c += a + b;

我的问题是,

c的最终结果是否也会产生小于10^-6的精度错误?

如果答案是否定的,那么我们怎么能真正知道这个精确度错误以及如果您按照自己的意愿和任何顺序应用任何类型的操作会发生什么?

3 个答案:

答案 0 :(得分:6)

  

浮点变量有精度6,(如果我理解正确的话)意味着计算机实际存储的数量与你想要的实际数量之间的差异将小于10 ^ -6

     

这意味着a和b都有一些小于10 ^ -6

的错误

10 -6 图是将任意常数表示为浮点数时相对精度的粗略度量。并非所有数字都以绝对误差10 -6 表示。例如,可以预期数字8765432.1大约表示单位。如果您至少有点幸运,那么在将其表示为float时,您将获得8765432。另一方面,可以预期1E-15f表示绝对误差至多约10 -21

  

所以在计算机内部实际上可能是1.229100000012123而b可能是3.9900000191919

不,抱歉,它的工作方式并不是你编写整个数字并为可能的错误添加六个零。可以通过从前导数字计算六个零来估算误差,而不是从最后一个数字计算。在这里,你可以期待1.22910012123或3.990000191919。

(实际上你会得到正好1.2290999889373779296875和3.9900000095367431640625。不要忘记表示错误可以是负数也可以是正数,因为它是第一个数字。)

  

现在让我们说你有以下代码[...]

     

我的问题是,

     

c的最终结果是否也会出现精度误差小于10 ^ -6的情况?

没有。总绝对误差将是ab的所有表示错误的总和,用于你使用它们的千次,以及你所做的2000次加法的错误。这是4000种不同的错误来源!其中许多将是相同的,其中一些将相互补偿,但最终结果可能不会达到10 -6 相对准确度,更像是10 -5 相对准确性(建议不计算)。

答案 1 :(得分:3)

这是一个非常好的问题,这个问题已经被许多权威机构解决了几十年,并且本身就是一门计算机科学学科(for example)。来自 What Every Computer Scientist Should Know About Floating-Point Arithmetic

  

浮点运算被很多人认为是一个深奥的主题。这是相当令人惊讶的,因为浮点在计算机系统中无处不在。几乎每种语言都有浮点数据类型;从PC到超级计算机的计算机都有浮点加速器;大多数编译器都会被要求不时编译浮点算法;几乎每个操作系统都必须响应溢出等浮点异常。本文提供了一个关于浮点的方面的教程,这些方面对计算机系统的设计者有直接影响。它以浮点表示的背景和舍入错误开始,继续讨论IEEE浮点标准,并以大量计算机构建器如何更好地支持浮点的例子结束。

(强调我的)

答案 2 :(得分:-2)

简短的回答是,您无法轻易确定长链浮点运算的精度。

"c += a + b"这样的操作的精度不仅取决于浮点实现的原始精度(现在几乎总是IEEE),还取决于a,b和c的实际值。 / p>

此外,编译器可能选择以不同的方式优化代码,这可能导致意外问题,例如将其转换为"c+=a; c+=b;"或简单地将循环作为"tmp = a*1000; tmp += b*1000; c += tmp;"或其他一些变体进行编译器将确定导致更快的执行时间但结果相同。

最重要的是,仅通过检查源代码就无法进行精度分析。

由于这个原因,许多人只是使用更高精度的实现,如double或long-double,然后检查精度问题是否已经用于所有实际目的。

如果这还不够,那么回退总是以整数实现所有逻辑并避免浮点数。