js為什么不能正確處理小數(shù)運(yùn)算?
var sum = 0; for(var i = 0; i < 10; i++) { sum += 0.1; } console.log(sum);
上面的程序會輸出1嗎?
在 你有必要知道的 25 個 JavaScript 面試題 一文中,第 8 個題淺顯的說了下 js 為什么不能正確處理小數(shù)運(yùn)算的問題。今天重拾舊題,更深層次的剖析下這個問題。
但要先說明的是,不能正確處理小數(shù)的運(yùn)算并不是 JavaScript 語言本身的設(shè)計錯誤,其它高級編程語言,如C,Java等,也是不能正確處理小數(shù)運(yùn)算的:
#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ī)器語言才能運(yùn)行,而對 CPU 來說,它不識別數(shù)的十進(jìn)制、八進(jìn)制和十六進(jìn)制等,我們在程序中聲明的這些進(jìn)制數(shù)都會被轉(zhuǎn)成二進(jìn)制數(shù)進(jìn)行運(yùn)算。
為什么不是轉(zhuǎn)換成三進(jìn)制數(shù)進(jìn)行運(yù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ù)的運(yùn)算中,所有操作數(shù)都會被轉(zhuǎn)成二進(jìn)制數(shù)參與運(yùn)算,如39,會被轉(zhuǎn)換成二進(jìn)制 00100111
小數(shù)的二進(jìn)制表示
如前文所說,程序中的數(shù)據(jù)都會被轉(zhuǎn)換成二進(jìn)制數(shù),小數(shù)參與運(yùn)算時,也會被轉(zhuǎn)成二進(jìn)制,如十進(jìn)制的11.1875 會被轉(zhuǎn)換成1101.0010。
小數(shù)點(diǎn)后 4 位用二進(jìn)制數(shù)表示的數(shù)值范圍是 0.0000~0.1111,因此,這只能表示 0.5、0.25、0.125、0.0625 這四個十進(jìn)制數(shù)以及小數(shù)點(diǎn)后面的位權(quán)組合(相加)而成的小數(shù):
從上表可以看出,十進(jìn)制數(shù) 0 的下一位是 0.0625,所以,0~0.0625 之間的小數(shù),就無法用小數(shù)點(diǎn)后 4 位數(shù)的二進(jìn)制數(shù)表示;如果增加二進(jìn)制數(shù)小數(shù)點(diǎn)后面的位數(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)為雙精度浮點(diǎn)型。按照 IEEE 的規(guī)定,單精度浮點(diǎn)數(shù)用 32 位表示全體小數(shù),而雙精度浮點(diǎn)數(shù)用 64 位表示全體小數(shù),而浮點(diǎn)數(shù)由符號、尾數(shù)、指數(shù)和基數(shù)組成,所以并不是所有的位數(shù)都用來表示小數(shù),符號、指數(shù)等也要占據(jù)位數(shù),基數(shù)不占據(jù)位數(shù):
雙精度浮點(diǎn)數(shù)的小數(shù)部分最多支持 52 位,所以兩者相加之后得到這么一串 0.0100110011001100110011001100110011001100…因浮點(diǎn)數(shù)小數(shù)位的限制而截斷的二進(jìn)制數(shù)字,這時候,再把它轉(zhuǎn)換為十進(jìn)制,就成了 0.30000000000000004。
總結(jié)
js 不能正確處理小數(shù)運(yùn)算,包括其它高級編程語言一樣,這不是語言本身的設(shè)計錯誤,而是計算機(jī)內(nèi)部本身就不能正確處理小數(shù)的運(yùn)算,對小數(shù)的運(yùn)算往往會得到意想不到的結(jié)果,因為并不是所有的十進(jìn)制小數(shù)能被二進(jìn)制表示。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助。
- JavaScript 正則表達(dá)式 驗證整數(shù)、小數(shù)、實數(shù)、有效位小數(shù)最簡單
- js 小數(shù)取整的函數(shù)
- JS保留小數(shù)點(diǎn)(四舍五入、四舍六入)實現(xiàn)思路及實例
- JS格式化數(shù)字金額用逗號隔開保留兩位小數(shù)
- js取float型小數(shù)點(diǎn)后兩位數(shù)的方法
- js中小數(shù)轉(zhuǎn)換整數(shù)的方法
- js數(shù)字轉(zhuǎn)換為float,取N位小數(shù)
- Javascript浮點(diǎn)數(shù)乘積運(yùn)算出現(xiàn)多位小數(shù)的解決方法
- js小數(shù)運(yùn)算出現(xiàn)多位小數(shù)如何解決
相關(guān)文章
基于Javascript實現(xiàn)二級聯(lián)動菜單效果
這篇文章主要為大家詳細(xì)介紹了基于Javascript實現(xiàn)二級聯(lián)動菜單效果的相關(guān)資料,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-03-03微信小程序?qū)崿F(xiàn)語音識別轉(zhuǎn)文字功能及遇到的坑
這篇文章主要介紹了小程序?qū)崿F(xiàn)語音識別轉(zhuǎn)文字功能,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友可以參考下2019-08-08JavaScript返回網(wǎng)頁中超鏈接數(shù)量的方法
這篇文章主要介紹了JavaScript返回網(wǎng)頁中超鏈接數(shù)量的方法,使用javascript中的document.links實現(xiàn)這一功能,需要的朋友可以參考下2015-04-04