美文网首页
浮点数陷阱

浮点数陷阱

作者: 气旋_c8b6 | 来源:发表于2019-04-09 14:50 被阅读0次

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

    相关文章

      网友评论

          本文标题:浮点数陷阱

          本文链接:https://www.haomeiwen.com/subject/nsebiqtx.html