浮点数陷阱

一旦我们越过了Acheron,我们就到达了第一层,这是一个善良的异教徒的家。这些人忽视浮点神,他们相信

.1=.3/3

是对的。他们同时相信

seq(0, 1, by=.1) == .3

会有一个值为TRUE。但是你不应该相信

unique(c(.3, .4 - .1, .5 - .2, .6 - .3, .7 - .4))

只会有一个结果。

我的第一个程序实在石器时代末期写的,任务是解二次方程。石器时代是指我们使用打孔卡进行编程,在穿孔机上没有删除键——一旦打了孔就没有办法修改。因此行尾的错误意味着你必须丢弃整张卡片,并由该行重新开始。我对整个过程非常熟悉。
在经过长期考验获得一包正确穿孔卡片后,欢乐随之而来,然而只是短暂的快乐。 下一步是将一叠卡片放入由计算机操作员监控的收纳篮中。几个小时后,输出的纸质结果会出现在纸箱中。这个程序中当然有错误。经过与穿孔机的另一次斗争(这次相对简短),卡片回到了篮子里。
在我意识这个报错只是告诉我程序运行过程中遇到第一个错误之前,程序还并没有进行太多次数的迭代。最终,在第三天,输出中没有报错信息,有一个答案——一个错误的答案。二次方程是一个非常简单的方程,答案显然是2和3,程序输出的结果是s 1.999997和3.000001。之前的时间已经让我够痛苦的了,然而它却甚至得不到一个正确的答案。
下面我用R语言写一下这个函数:

> quadratic.formula
function(a,b,c){
 rad <- b^2-4*a*c
 if(is.complex(rad)||all(rad>=0)){
   rad <- sqrt(rad)
 }else{
   rad <- sqrt(as.complex(rad))
 }
 cbind(-b - rad,-b + rad)/(2*a)
}
> quadratic.formula(1, -5, 6)
    [,1] [,2]
[1,]    2    3
> quadratic.formula(1, c(-5, 1), 6)
              [,1]           [,2]
[1,]  2.0+0.000000i  3.0+0.000000i
[2,] -0.5-2.397916i -0.5+2.397916i

上面的函数比之前的程序更具有一般性,但重要的是得到2和3这个答案。R仅仅是print,以便大多数数值错误(numerical error)是不可见的。通过减去正确的答案,我们可以看出他实际上有多么的错误:

> quadratic.formula(1, -5, 6) - c(2, 3)
     [,1] [,2]
[1,]    0    0

嗯,这种情况下得到的是正确的答案。但是如果我们稍微修改一下,他就会出现错误:

> quadratic.formula(1/3, -5/3, 6/3)
     [,1] [,2]
[1,]    2    3
print(quadratic.formula(1/3, -5/3, 6/3), digits=16)
                  [,1]              [,2]
[1,] 1.999999999999999 3.000000000000001
#digits<15时,结果仍然是2和3
> quadratic.formula(1/3, -5/3, 6/3) - c(2, 3)
              [,1]         [,2]
[1,] -1.110223e-15 1.332268e-15

R很擅长隐藏数值错误,导致我们很容易忘记他的存在。每当一个浮点运算结束,即使是一个简单的运算,你都应当假设会出现数值错误(numerical error)。如果没有错误你应该感到庆幸,而不是觉得理应如此。你可以使用all.equal替代==对浮点数是否相等进行判断。如果你有一个数字逻辑上是整数,但是该数字经过了一些运算,你可以使用round判断他们是不是整数。
不要将数值错误(numerical error)与错误(error)混淆。错误(error)是不正确的执行计算,数值错误(numerical error)是数字表示的局限性而产生的噪声。1/3表示为33%是数值错误(numerical error)而不是错误(error)。
我们已经见过了异教徒信仰的另一方面:输出的结果就是全部

> 7/13 - 3/31
[1] 0.4416873

R输出结果在默认情况下只显示部分,并不是全部:

> print(7/13 - 3/31, digits=16)
[1] 0.4416873449131513

一些函数显示的更为简略:

> summary(7/13 - 3/31) 
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
 0.4417  0.4417  0.4417  0.4417  0.4417  0.4417 

有限算数的数值错误(numerical error)不仅会模糊答案,还会模糊问题。 在数学中,矩阵的秩是某个特定的整数。 在计算中,矩阵的秩是一个模糊的概念。由于特征值不必是明确为零或非零,因此秩不一定是一个明确的数字。(这说了啥)

现在我们准备去下一层,Minos咬牙切齿的站在那里。他自我缠绕的圈数标识着他面前人们的罪恶。

-------

Acheron:阿刻戎河在意大利诗人但丁的《神曲》中是地狱的边界;在希腊神话是地狱五条主要河流之一。阿刻戎河上有一位摆渡者名叫卡戎,负责把刚死去的亡灵送到河对岸的地狱界。据说卡戎对每位渡河的亡灵都要收取少量船费,付不起船费的亡灵只能长期徘徊在河岸边。

你可能感兴趣的:(浮点数陷阱)