【数值分析】0.4 有效数字缺失
Abstract: 本文介绍计算机在计算中有可能引发的有效数字缺失
Keywords: 有效数字缺失
Keywords: 有效数字缺失
有效数字缺失
对计算机硬件或者底层功能足够了解,虽然表面教条枯燥,但是我们能在其中学到很多有可能出现,但是不容易察觉的陷阱
有效数字
在了解有效数字缺失之前,我们有必要确定下什么是有效数字,无论是小数还是大数,我们都能写成科学计数法的形式,在十进制下我们可以把所有数字写成:
的这种形式,其中 ,有效数字是 共 位,注意我们这里之研究数学上的有效数字,物理中测量还有另一套说法,我们不考虑.
有效数字我们知道是什么了,那么什么情况下会缺失呢?数字不会凭空消失,一定是做了某种计算后,原本有 位有效数字,结果变成了小于 位,这就是缺失,而缺失不可能发生在右侧,也就是 这一侧,原因是,如果这些位消失了,我们依然可以补充0作为有效数字,所以我们要注意左侧的数字。
比如:
这时候,我们原本的7位有效数字,瞬间变成1位,有问题么?没有问题,因为这是准确结果,但是从数值上看,有效数字减少了。
但是,如果减法的两个操作数,减数或者被减数,并不是一个确定的数,而是一个表达式,包含无限的小数呢?
但是,如果减法的两个操作数,减数或者被减数,并不是一个确定的数,而是一个表达式,包含无限的小数呢?
“减法”=“陷阱”
考虑 这个表达式的值。
这个例子很简答,输入matlab能够直接得到答案, 所以 减法之前有七位有效数字,结果有4位有效数字,也就是少了3位,这看起来没啥。
然后我们假定,我们有一种特殊的计算机,其浮点数最多只能保存十进制的3位有效数字,(书中说是三位计算机,表达不是很准确,会和三个二进制位混淆,所以我们说这个计算机只能计算3位十进制)那么我们如果按照上面的计算过程,那么会得到:
这个例子很简答,输入matlab能够直接得到答案, 所以 减法之前有七位有效数字,结果有4位有效数字,也就是少了3位,这看起来没啥。
然后我们假定,我们有一种特殊的计算机,其浮点数最多只能保存十进制的3位有效数字,(书中说是三位计算机,表达不是很准确,会和三个二进制位混淆,所以我们说这个计算机只能计算3位十进制)那么我们如果按照上面的计算过程,那么会得到:
结果是0,第一步我们把3.001662保存成3.00 的原因是计算机只能保存3位十进制数,所以这个结果是截断误差造成的,然后相减得到了|0.00,理想情况,有效数字是1.66,可见一个都不对。
我们这里所说的有效数字是和真实计算结果数字上的比较,不是比较大小,只考虑尾数,不考虑指数。
两个相近的数相减,可能会造成有效数字的缺失
但是你可能说,没办法,这是机器的限制,你那个能存一百位有效数字的计算机来就可以了,如果你这么想,那就没得聊了,
有没有办法?当然有办法!
解决方法
解决办法的核心思想是:把相近的两个数变成不相近的!
同样使用只有三维有效数字的计算机
同样使用只有三维有效数字的计算机
上面这种方法叫做共轭等式,可以避免两个相近的数字相减。下面我们看另一个例子,主要技巧也是用一些恒等式:
明显得当 的时候 那么就有可能造成有效数字缺失,与上面类似的,我们也有共轭等式:
然后我们就写个代码来观察下 和 在 的时候的表现,是否 更准确,我们写一段python程序:
1 2 3 4 5 6 7 8 9 | import math x=1.0 for i in range(0,16): x=x/10 cos_x=math.cos(x) sin_x=math.sin(x) e1=(1- cos_x)/pow(sin_x,2) e2 = (1 ) / (1 + cos_x) print '|%1.16f|%1.16f|%1.16f|' % (x,e1,e2) |
运行结果是:
0.1000000000000000 | 0.5012520862885769 | 0.5012520862885712 |
0.0100000000000000 | 0.5000125002084805 | 0.5000125002083363 |
0.0010000000000000 | 0.5000001249921894 | 0.5000001250000208 |
0.0001000000000000 | 0.4999999986279311 | 0.5000000012500000 |
0.0000100000000000 | 0.5000000413868522 | 0.5000000000125000 |
0.0000010000000000 | 0.5000444502913370 | 0.5000000000001250 |
0.0000001000000000 | 0.4996003610813219 | 0.5000000000000012 |
0.0000000100000000 | 0.0000000000000000 | 0.5000000000000000 |
0.0000000010000000 | 0.0000000000000000 | 0.5000000000000000 |
0.0000000001000000 | 0.0000000000000000 | 0.5000000000000000 |
0.0000000000100000 | 0.0000000000000000 | 0.5000000000000000 |
0.0000000000010000 | 0.0000000000000000 | 0.5000000000000000 |
0.0000000000001000 | 0.0000000000000000 | 0.5000000000000000 |
0.0000000000000100 | 0.0000000000000000 | 0.5000000000000000 |
0.0000000000000010 | 0.0000000000000000 | 0.5000000000000000 |
0.0000000000000001 | 0.0000000000000000 | 0.5000000000000000 |
从 0.00000001开始 崩溃,而 保持稳定。
到0.00000001崩溃的原因是cos在这个位置截断后就是1.0:
到0.00000001崩溃的原因是cos在这个位置截断后就是1.0:
同样,我们这套方法的核心就是不要见相近的数字,只要有减法就要小心,注意前后两个数是否相近,另一个例子是二次方程的求解,对于公式法我们必须要计算:
其中要注意的是
对应的方法就是把这个计算改成:
当然这里面还有问题就是 的部分依然存在减法
而且 是负数的时候,依然会存在 相近的情况,尤其是 的时候,这时候计算最好使用:
总结
有效数字可能会带来很小的误差,也可以带来很大的误差,所以,不管什么时候,我们能避免减法就避免减法,尤其减法的两个数字接近的时候,这个时候更危险。
沒有留言:
張貼留言