• <noscript id="ecgc0"><kbd id="ecgc0"></kbd></noscript>
    <menu id="ecgc0"></menu>
  • <tt id="ecgc0"></tt>

    什么?計算機也會算錯數?

    人們通常不會懷疑計算機在數學計算上的結果,畢竟,如果連數都算不對,那還叫什么“計算機”啦?其實,有個簡單的題目就能讓計算機算錯,不信我們試試看。

    如果你用Chrome瀏覽器的話,按下F12(在Mac上要按Command+Option+I)可以打開一個“開發者工具”窗口,然后點上面的“Console”標簽,你會看到一個控制臺窗口,在里面輸入“0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1”(一共10個0.1),按下回車,看看結果是什么?

    矮馬,嚇死本寶寶了,明眼人一看就知道算錯了是吧?10個0.1加起來應該等于1啊!不過如果你試一下“0.1*10”,咦,這次結果又對了!這什么鬼?好吧,放心,你的電腦沒壞,我們來看看這到底是怎么回事。

    稍早接觸計算機的那一代人幾乎都知道計算機的內部運算都是以二進制來進行的,然而現在的用戶恐怕早就不關心這件事了。自從馮·諾依曼提出現代計算機架構以來,幾十年了計算機的原理都沒有什么根本性的變化。我們人類在日常生活中通常使用十進制,有一種說法認為這是因為人有10個手指,但在電路設計上要表示10個狀態可就相當困難了,不過很多元件都可以很容易地表示兩個狀態,比如開和關,電平高和低,因此采用二進制對于計算機來說是一個最方便的設計。而正是因為人類和計算機使用的進制不同,因此在進行計算時,就必然會涉及到進制的轉換,也就是說,我們在屏幕上輸入的是十進制的數字,然后計算機要將它轉換成二進制進行計算,然后再把計算的結果轉換成十進制顯示出來。之所以上面那個題目計算機會算錯,本質上說就是二進制惹的禍。

    要搞清楚這個問題,我們先來理解一下進制的概念。在十進制中,一位數字我們可以使用0到9,比9多的時候就會變成10,這就是一個兩位數了,也就是進位了,二進制也是一樣,只不過一位數字只能使用0和1,再多就要進位了。那么進制的本質又是什么呢?我們隨便拿一個十進制的數字來看一看:


    看懂了沒?一個十進制數實際上就是其中每一位數依次乘以10的0、1、2…次冪(權重),然后再把結果加起來,那么以此類推,二進制里面就是把上面的10換成2唄?我們來看一個:

    于是二進制數1001也就是十進制數的9。到這里似乎還沒什么問題,因為我們只討論了整數呢,每一個十進制整數都可以轉換成一個二進制整數,反過來,每一個二進制整數也都可以轉換成一個十進制整數。不過,如果把小數也加進來呢?先看一個十進制的小數:

    看懂了沒?其實就是把10上面的指數變成了負數而已,不難吧。那么以此類推,二進制的小數也就是把10換成2唄,我們來看一個:


    上面我們理解了進制的一些本質特性,算不過來也沒關系,我們暫且先不管它,不過,這跟我們遇到的問題到底有什么關系?別急,我們再看一下當引入小數之后,進制之間的轉換到底出了什么bug。我們知道實數的數軸是連續的,每兩個數字之間的部分是可以被無限分割的,舉個例子,0和1之間的這部分,如果用十進制一位小數來分割的話,可以分成10份,也就是0.1、0.2、0.3……0.9、1,如果用二進制一位小數來分割的話,則只能分成兩份,也就是0.1(十進制的0.5)、1。你發現了什么問題?無論小數點后面增加多少位數字,二進制永遠只能以2來分割數軸,而十進制則是以10來分割數軸。

    讓我們回想一下小學的數學知識,在十進制中,如果要用有限小數來表示一個分數的值,那么這個分數的分母(化簡之后)一定不能包含除了2和5以外的其他質因數,因為十進制以10來分割數軸,而10分解質因數的結果為2×5。舉個例子:1/8、1/10、1/25都可以換算成有限小數(分別是0.125、0.1、0.04),因為這些分數的分母分解質因數之后只包含2或者5(8=2×2×2、10=2×5、25=5×5),而當分母包含其他質因數時,例如1/3、1/7、1/18這些則無法用有限小數來表示(也就是俗話說的“除不盡”)。如果我們把這個規律套用到二進制上會怎么樣呢?2本身就是一個質數,無法分解質因數了,因此在二進制中,如果要用有限小數來表示一個分數的值,那么這個分數的分母一定只能包含2這一個質因數,換句話說,分母必須為2的冪(2、4、8、16、32……)。

    好了,我們回頭看看開頭的題目,0.1換算成分數就是1/10,而1/10的分母是10,10并不是2的冪,因此,在二進制中并不能用有限小數來表示1/10這個值。事實上,如果將0.1轉換成二進制,我們會得到一個無限循環小數:0.000110011001100……看到這里,很多人估計已經想明白了,沒錯,計算機的精度是有限的,并不能直接處理無限小數,對于無限小數必須要截短到某個位置把它變成有限小數,但截短之后這個數就不準了,必然就產生了一點誤差,而連續加10次會將這種誤差放大,當誤差被放大到一定程度時,計算的結果就會出問題了,于是我們就看到了開頭的那一幕。如果用十進制來類比的話,大家可以想象一下,1/3+1/3+1/3=1,但1/3只能用無限循環小數來表示,即0.333333……,如果我們將它截短到某一位,假設截到0.333,那么0.333+0.333+0.333=0.999,你看,同樣也會出問題。

    問題的原因總算搞清楚了,不過感覺很坑爹啊,計算機居然算不準小數,但為什么平時大家很少因此遇到問題呢?那是因為大多數用戶都不用編寫程序,但對于整天編寫程序的程序員來說,這樣的問題其實經常遇到。比如說,如果你在一段程序中需要讓計算機判斷0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1是否等于1,計算機會告訴你不等于1,坑爹吧?如果這段程序涉及到算錢,有時候就會錯得很離譜,因此有經驗的程序員在碰到小數計算的時候都會特別小心。當然,作為一般用戶我們平時根本不需要關心這樣的問題,不過計算機居然會算錯數,怎么想都覺得挺奇妙的吧?

    • 發表于 2015-11-02 00:00
    • 閱讀 ( 1056 )
    • 分類:其他類型

    你可能感興趣的文章

    相關問題

    0 條評論

    請先 登錄 后評論
    admin
    admin

    0 篇文章

    作家榜 ?

    1. xiaonan123 189 文章
    2. 湯依妹兒 97 文章
    3. luogf229 46 文章
    4. jy02406749 45 文章
    5. 小凡 34 文章
    6. Daisy萌 32 文章
    7. 我的QQ3117863681 24 文章
    8. 華志健 23 文章

    聯系我們:uytrv@hotmail.com 問答工具
  • <noscript id="ecgc0"><kbd id="ecgc0"></kbd></noscript>
    <menu id="ecgc0"></menu>
  • <tt id="ecgc0"></tt>
    久久久久精品国产麻豆