var sum = 0;for(var i = 0; i < 10; i++) { sum += 0.1;}console.log(sum);上面的程序會輸出1嗎?
在 你有必要知道的 25 個 JavaScript 面試題 一文中,第 8 個題淺顯的說了下 js 為什么不能正確處理小數(shù)運算的問題。今天重拾舊題,更深層次的剖析下這個問題。
但要先說明的是,不能正確處理小數(shù)的運算并不是 JavaScript 語言本身的設(shè)計錯誤,其它高級編程語言,如C,Java等,也是不能正確處理小數(shù)運算的:
#include <stdio.h>void main(){  float sum;  int i;    sum = 0;    for(i = 0; i < 100; i++) {    sum += 0.1;  }    printf('%f/n', sum); //10.000002}數(shù)在計算機(jī)內(nèi)部的表示
我們都知道,用高級編程語言編寫的程序需要經(jīng)過解釋、編譯等操作轉(zhuǎn)變成 CPU(Central Processing Unit) 可以識別的機(jī)器語言才能運行,而對 CPU 來說,它不識別數(shù)的十進(jìn)制、八進(jìn)制和十六進(jìn)制等,我們在程序中聲明的這些進(jìn)制數(shù)都會被轉(zhuǎn)成二進(jìn)制數(shù)進(jìn)行運算。
為什么不是轉(zhuǎn)換成三進(jìn)制數(shù)進(jìn)行運算呢?
計算機(jī)內(nèi)部是由很多的 IC (Integrated Circuit: 集成電路) 這種電子部件構(gòu)成的,它的長相大概是這樣子:

IC 有很多種形狀,在其兩側(cè)或內(nèi)部并排排列著很多引腳(圖示只畫出了一側(cè))。IC 的所有引腳,只有直流電壓 0V 或 5V 兩個狀態(tài),即一個 IC 引腳只能表示兩個狀態(tài)。IC 的這個特性就決定了計算機(jī)內(nèi)部的數(shù)據(jù)只能用二進(jìn)制數(shù)處理。
由于1 位(一個引腳)只能表示兩個狀態(tài),所以二進(jìn)制的計算方式就變成了 0、1、10、11、100….這種形式:

所以,在數(shù)的運算中,所有操作數(shù)都會被轉(zhuǎn)成二進(jìn)制數(shù)參與運算,如39,會被轉(zhuǎn)換成二進(jìn)制 00100111
小數(shù)的二進(jìn)制表示
如前文所說,程序中的數(shù)據(jù)都會被轉(zhuǎn)換成二進(jìn)制數(shù),小數(shù)參與運算時,也會被轉(zhuǎn)成二進(jìn)制,如十進(jìn)制的11.1875 會被轉(zhuǎn)換成1101.0010。
小數(shù)點后 4 位用二進(jìn)制數(shù)表示的數(shù)值范圍是 0.0000~0.1111,因此,這只能表示 0.5、0.25、0.125、0.0625 這四個十進(jìn)制數(shù)以及小數(shù)點后面的位權(quán)組合(相加)而成的小數(shù):

從上表可以看出,十進(jìn)制數(shù) 0 的下一位是 0.0625,所以,0~0.0625 之間的小數(shù),就無法用小數(shù)點后 4 位數(shù)的二進(jìn)制數(shù)表示;如果增加二進(jìn)制數(shù)小數(shù)點后面的位數(shù),與其相對應(yīng)的十進(jìn)制數(shù)的個數(shù)也會增加,但無論增加多少位,都無法得到 0.1 這個結(jié)果。實際上,0.1 轉(zhuǎn)換成二進(jìn)制是 0.00110011001100110011…… 注意 0011 是無限重復(fù)的:
console.log(0.2+0.1);//操作數(shù)的二進(jìn)制表示0.1 => 0.0001 1001 1001 1001…(無限循環(huán))0.2 => 0.0011 0011 0011 0011…(無限循環(huán))
js 的 Number 類型并沒有像 C / Java 等分整型、單精度、雙精度等,而是統(tǒng)一表現(xiàn)為雙精度浮點型。按照 IEEE 的規(guī)定,單精度浮點數(shù)用 32 位表示全體小數(shù),而雙精度浮點數(shù)用 64 位表示全體小數(shù),而浮點數(shù)由符號、尾數(shù)、指數(shù)和基數(shù)組成,所以并不是所有的位數(shù)都用來表示小數(shù),符號、指數(shù)等也要占據(jù)位數(shù),基數(shù)不占據(jù)位數(shù):

雙精度浮點數(shù)的小數(shù)部分最多支持 52 位,所以兩者相加之后得到這么一串 0.0100110011001100110011001100110011001100…因浮點數(shù)小數(shù)位的限制而截斷的二進(jìn)制數(shù)字,這時候,再把它轉(zhuǎn)換為十進(jìn)制,就成了 0.30000000000000004。
總結(jié)
js 不能正確處理小數(shù)運算,包括其它高級編程語言一樣,這不是語言本身的設(shè)計錯誤,而是計算機(jī)內(nèi)部本身就不能正確處理小數(shù)的運算,對小數(shù)的運算往往會得到意想不到的結(jié)果,因為并不是所有的十進(jìn)制小數(shù)能被二進(jìn)制表示。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助。
新聞熱點
疑難解答