2009-02-02 65 views
7

我收到的一项最近的家庭作业要求我们采取措辞,在计算机上执行时可能会造成精度损失,并对其进行修改,以避免造成损失。避免精度损失的最佳算法?

不幸的是,这样做的方向尚未明确。通过观察正在执行的各种示例,我知道有一些方法可以做到这一点:使用泰勒级数,如果涉及平方根使用共轭,或者在减去两个分数时找到共同的分母。

但是,我在准确发现精确度丢失时会发生一些麻烦。到目前为止,我唯一知道的是,当你减去接近于相同的两个数字时,由于高位数字很重要,所以会出现精度损失,并且你会从四舍五入中丢失这些数字。

我的问题是我应该寻找哪些其他常见情况,以及哪些被认为是接触它们的“好”方法?

例如,这里有一个问题:

f(x) = tan(x) − sin(x) when x ~ 0 

什么是评价这一点这三个选项的最佳和最差的算法:

(a) (1/ cos(x) − 1) sin(x), 
(b) (x^3)/2 
(c) tan(x)*(sin(x)^2)/(cos(x) + 1). 

我明白,当x接近零,tan(x)和sin(x)几乎相同。我不明白如何或为什么这些算法对于解决问题更好或更差。

回答

5

通常使用的另一个经验法则是:当添加一长串数字时,开始从最接近零的数字开始添加,并以最大数字结束。

解释为什么这是好的只是棘手。当你为大数添加小数时,它们有可能被完全丢弃,因为它们比当前大数的尾数小。就拿这样的情况:

a = 1,000,000; 
do 100,000,000 time: 
    a += 0.01; 

如果0.01比最低的尾数数字越小,则循环不执行任何操作而最终的结果是==百万 但如果你这样做是这样的:

a = 0; 
do 100,000,000 time: 
    a += 0.01; 
a += 1,000,000; 

比低数字慢慢增长,你更可能最终接近一个== 2,000,000这是正确的答案。
这是一个极端的例子,但我希望你明白。

4

当我还是一名本科生时,我不得不接受一个数学课,而且这是非常痛苦的。无论如何,IEEE 754是典型的由现代CPU实现的浮点标准。了解它的基础知识是有用的,因为这给你很多关于不该做什么的直觉。它的简单解释是计算机存储浮点数,如基数为2的科学记数法,指数和尾数的位数都是固定的。这意味着数字的绝对值越大,其表示的精确度越低。对于IEEE 754中的32位浮点数,一半的可能位模式表示-1和1之间,即使可以用32位浮点数表示大约10^38的数字。对于大于2^24(大约16.7百万)的值,32位浮点数不能完全表示所有整数。

这意味着什么,你是,你通常需要避免以下几点:

  1. 有当最后的答案有望成为小中间值大。
  2. 在大数上加/减小数。例如,如果你写的东西,如:用于

    (浮点指数= 17000000;指数< 17000001;指数++){}

这个循环将永远不会终止监守17000000 + 1向下取整到17000000。 如果你有这样的事情:

float foo = 10000000 - 10000000.0001 

foo的值是0,没有-0.0001,由于舍入误差。

1

另一件事情,以避免被减去几乎是相同的数字,因为这也可能导致对舍入误差的敏感性增加。对于接近0的值,cos(x)将接近于1,所以1/cos(x)-1是那些你希望尽可能避免的减法之一,所以我应该说(a)应该被避免。

2

我的问题是什么是我应该寻找 一些其他 常见的情况,什么被认为是“好”接近他们的 方法呢?

有几种方法可以导致严重或甚至灾难性的精度损失。

最重要的原因是浮点数有位数量有限,e.g..doubles有53位。这意味着,如果您的“无用”数字不属于解决方案的一部分,但必须存储,您将失去精确度。

例如(我们使用十进制类型示范):

2.598765000000000000000000000100 -

2.598765000000000000000000000099

有趣的部分是100-99 = 1的答案。由于2.598765在两种情况下均相同,因此它 不会更改结果,但会浪费8位数。更糟糕的,因为电脑不 知道数字是没有用的,它是被迫来存储它和之后的CRAM 21个零, 浪费在所有29位。不幸的是,没有办法规避差异, ,但还有其他的情况,例如, exp(x)-1这是物理学中经常出现的函数。

0附近的exp函数几乎是线性的,但它强制执行1作为前导数字。因此,与12个 显著数字 EXP(0.001)-1 = 1.00100050017 - 1 = 1.00050017e-3

如果我们使用而不是函数的expm1()中,使用泰勒级数:

1 + X + X3^2/2 + x^3/6 ...-1 =

X + X^2/2 + X^3/6 =:的expm1(X)

的expm1(0.001)= 1.00500166667e -3-

好得多。

第二个问题是函数的斜率非常陡,如x的切线接近pi/2。 tan(11)的斜率为50000,这意味着由于舍入误差 而引起的任何小偏差都将被因子50000放大!或者你有奇点,例如,结果接近0/0,这意味着它可以有任何值。

在这两种情况下,您都会创建一个替代函数,简化原始函数。突出显示不同的解决方案是没有用的,因为如果没有经过培训,您根本就不会“首先”看到问题。

一本很好的学习和训练的书:Forman S. Acton:Real Computing made real