2017-06-14 171 views
-1

在C语言中(以及其他许多语言中)使用整数时,必须注意精度的划分。在分割之前,增加和增加东西总是会更好(因此创造更大的中介结果,只要它不溢出)。C思维:浮点数与整数和浮点数表示法

但是漂浮物呢?这仍然有效吗?或者它们是以这样一种方式表示的:最好将相似数量级的数量而不是大数量的数量分成小数量级?

+0

首先你需要了解浮标如何在内存中表示,参见[这个答案](https://softwareengineering.stackexchange.com/a/215126/235262)(软件工程) –

+0

你是什么意思在使用Integer时必须注意精度?如果你划分一个整数,你正在使用整数除法和所有的后果,精度是第十个十进制数字。在这个意义上整数除法是精确的。 –

+1

在做浮点运算时保持最小舍入误差是一个相当大的话题。作为一个简单的规则,如果操作数具有相似的幅度,那么最好。例如:将一个小浮点值添加到一个巨大的float值,根本不会改变巨大的值(假设两者之间的差异足够大)。 – 4386427

回答

3

浮筒/双打和类似浮点工作的表示,是面向护的显著数字号码(又名“精度”),而不是一个固定数目的小数,如发生在定点或整数工作。

最好避免组合数量,这可能会导致指数方面的隐式下溢或溢出,即在浮点数范围的极限处。因此,在可能的情况下,应该避免并重新安排差别很大的数量(显式地或由于具有相反的符号)的加/减数量,以避免这种众所周知的路线失去精确度。

例子:这是更好地重构/重新排序

small + big + small + big + small * big 

(small+small+small) + big + big 

因为小商品独立可能使一个大的没有什么区别,因此他们的贡献可能会消失。

如果任何数量的低位有任何“噪音”或不精确,那么了解重要位的丢失如何通过计算传播也是明智的。

0

(用于整数)在分割之前,乘法和添加事物(因此创建更大的中间结果,只要它不溢出)总是更好。

这是否仍然成立(浮动)?

一般来说,答案是没有

这是很容易构建一个例子,其中将所有输入之前师会给你一个巨大的舍入误差。

假设你想添加百亿值和1000分他们再假定每个值是1。因此,预期的结果是10000000

方法1 但是,如果您之前添加的所有值除法,您将得到结果16777.216(对于32位浮点数)。正如你可以看到它几乎关闭。

方法2 因此,在将每个值除以1000之前,将它加到结果之前是否更好?如果你这样做,你会得到32768.0的结果(32位浮点数)。正如你所看到的,它也是非常不错的。

方法3 但是,如果你继续增加值,直到临时结果是超过100万更大然后除以1000的临时结果和中间结果添加到最终的结果,并重复已添加,直到总共10000000000个值,你会得到正确的结果。

因此,在处理浮点时,没有简单的“总是在添加之前添加”或“总是在添加之前进行分割”。作为一般规则,将操作数保持在相似的级别通常是一个好主意。这就是第三个例子。

2

整数:
只要没有溢出,+,-,*总是准确的。
使用除法,结果被截断,通常不等于数学答案。
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的计算中的误差变得显着。