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