在C语言中(以及其他许多语言中)使用整数时,必须注意精度的划分。在分割之前,增加和增加东西总是会更好(因此创造更大的中介结果,只要它不溢出)。C思维:浮点数与整数和浮点数表示法
但是漂浮物呢?这仍然有效吗?或者它们是以这样一种方式表示的:最好将相似数量级的数量而不是大数量的数量分成小数量级?
在C语言中(以及其他许多语言中)使用整数时,必须注意精度的划分。在分割之前,增加和增加东西总是会更好(因此创造更大的中介结果,只要它不溢出)。C思维:浮点数与整数和浮点数表示法
但是漂浮物呢?这仍然有效吗?或者它们是以这样一种方式表示的:最好将相似数量级的数量而不是大数量的数量分成小数量级?
浮筒/双打和类似浮点工作的表示,是面向护的显著数字号码(又名“精度”),而不是一个固定数目的小数,如发生在定点或整数工作。
最好避免组合数量,这可能会导致指数方面的隐式下溢或溢出,即在浮点数范围的极限处。因此,在可能的情况下,应该避免并重新安排差别很大的数量(显式地或由于具有相反的符号)的加/减数量,以避免这种众所周知的路线失去精确度。
例子:这是更好地重构/重新排序
small + big + small + big + small * big
为
(small+small+small) + big + big
因为小商品独立可能使一个大的没有什么区别,因此他们的贡献可能会消失。
如果任何数量的低位有任何“噪音”或不精确,那么了解重要位的丢失如何通过计算传播也是明智的。
(用于整数)在分割之前,乘法和添加事物(因此创建更大的中间结果,只要它不溢出)总是更好。
这是否仍然成立(浮动)?
一般来说,答案是没有
这是很容易构建一个例子,其中将所有输入之前师会给你一个巨大的舍入误差。
假设你想添加百亿值和1000分他们再假定每个值是1。因此,预期的结果是10000000
方法1 但是,如果您之前添加的所有值除法,您将得到结果16777.216(对于32位浮点数)。正如你可以看到它几乎关闭。
方法2 因此,在将每个值除以1000之前,将它加到结果之前是否更好?如果你这样做,你会得到32768.0的结果(32位浮点数)。正如你所看到的,它也是非常不错的。
方法3 但是,如果你继续增加值,直到临时结果是超过100万更大然后除以1000的临时结果和中间结果添加到最终的结果,并重复已添加,直到总共10000000000个值,你会得到正确的结果。
因此,在处理浮点时,没有简单的“总是在添加之前添加”或“总是在添加之前进行分割”。作为一般规则,将操作数保持在相似的级别通常是一个好主意。这就是第三个例子。
整数:
只要没有溢出,+,-,*
总是准确的。
使用除法,结果被截断,通常不等于数学答案。
ia,ib,ic
,除以前的乘积ia*ib/ic
vs ia*(ib/ic)
更好,因为商是基于产品的更多位而不是ib
。
浮点数:
问题很微妙。再次,只要没有超过/下溢,顺序或*,/
序列的影响比整数小。 FP */-
类似于添加/减少日志。典型结果在数学正确答案的0.5 ULP之内。
随着FP和+,-
的fa,fb,fc
结果可以具有比数学正确一个显著差异1)值相距很远的幅度时,或2)减去几乎相等,并在先前的计算现在成为显著误差值。
考虑二次方程:
double d = sqrt(b*b - 4*a/c); // assume b*b - 4*a/c >= 0
double root1 = (-b + d)/(2*a);
double root2 = (-b - d)/(2*a);
对战
double d = sqrt(b*b - 4*a/c); // assume b*b - 4*a/c >= 0
double root1 = (b < 0) ? (-b + d)/(2*a) : (-b - d)/(2*a)
double root2 = c/(a*root1); // assume a*root1 != 0
第二届具有更好的root2
精度结果,当一个根接近0和|b|
几乎d
。这是因为b,d
减法取消了许多位的显着性,允许d
的计算中的误差变得显着。
首先你需要了解浮标如何在内存中表示,参见[这个答案](https://softwareengineering.stackexchange.com/a/215126/235262)(软件工程) –
你是什么意思在使用Integer时必须注意精度?如果你划分一个整数,你正在使用整数除法和所有的后果,精度是第十个十进制数字。在这个意义上整数除法是精确的。 –
在做浮点运算时保持最小舍入误差是一个相当大的话题。作为一个简单的规则,如果操作数具有相似的幅度,那么最好。例如:将一个小浮点值添加到一个巨大的float值,根本不会改变巨大的值(假设两者之间的差异足够大)。 – 4386427