淺談JavaScript中小數(shù)和大整數(shù)的精度丟失
來源:易賢網(wǎng) 閱讀:1333 次 日期:2016-06-17 16:13:24
溫馨提示:易賢網(wǎng)小編為您整理了“淺談JavaScript中小數(shù)和大整數(shù)的精度丟失”,方便廣大網(wǎng)友查閱!

下面小編就為大家?guī)硪黄獪\談JavaScript中小數(shù)和大整數(shù)的精度丟失。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。

先來看兩個問題:

0.1 + 0.2 == 0.3; // false

9999999999999999 == 10000000000000000; // true

第一個問題是小數(shù)的精度問題,在業(yè)界不少博客里已有討論。第二個問題,去年公司有個系統(tǒng)的數(shù)據(jù)庫在做數(shù)據(jù)訂正時,發(fā)現(xiàn)有部分?jǐn)?shù)據(jù)重復(fù)的詭異現(xiàn)象。本文將從規(guī)范出發(fā),對上面的問題做個小結(jié)。

最大整數(shù)

JavaScript 中的數(shù)字是用 IEEE 754 雙精度 64 位浮點(diǎn)數(shù) 來存儲的,其格式為:

s x m x 2^e

s 是符號位,表示正負(fù)。 m 是尾數(shù),有 52 bits. e 是指數(shù),有 11 bits. 在 ECMAScript 規(guī)范 里有給出 e 的范圍為 [-1074, 971]. 這樣,很容易推導(dǎo)出 JavaScript 能表示的最大整數(shù)為:

1 x (2^53 - 1) x 2^971 = 1.7976931348623157e+308

這個值正是 Number.MAX_VALUE

同理可推導(dǎo)出 Number.MIN_VALUE 的值為:

1 x 1 x 2^(-1074) = 5e-324

注意 MIN_VALUE 表示最接近 0 的正數(shù),而不是最小的數(shù)。最小的數(shù)是 -Number.MAX_VALUE

小數(shù)的精度丟失

JavaScript 的數(shù)字都是雙精度浮點(diǎn)數(shù),在計算機(jī)里用二進(jìn)制存儲。當(dāng)有效位數(shù)超過 52 位時,會存在精度丟失。比如:

十進(jìn)制 0.1 的二進(jìn)制為 0.0 0011 0011 0011 … (循環(huán) 0011)

十進(jìn)制 0.2 的二進(jìn)制為 0.0011 0011 0011 … (循環(huán) 0011)

0.1 + 0.2 相加可表示為:

   e = -4; m = 1.10011001100...1100(52 位)

 + e = -3; m = 1.10011001100...1100(52 位)

---------------------------------------------

   e = -3; m = 0.11001100110...0110

 + e = -3; m = 1.10011001100...1100

---------------------------------------------

   e = -3; m = 10.01100110011...001

---------------------------------------------

 = 0.01001100110011...001

 = 0.30000000000000004(十進(jìn)制)

根據(jù)上面的演算,還可以得出一個結(jié)論:當(dāng)十進(jìn)制小數(shù)的二進(jìn)制表示的有限數(shù)字不超過 52 位時,在 JavaScript 里是可以精確存儲的。比如:

0.05 + 0.005 == 0.055 // true

進(jìn)一步的規(guī)律,比如:

0.05 + 0.2 == 0.25 // true

0.05 + 0.9 == 0.95 // false

需要考慮 IEEE 754 的 Rounding modes, 有興趣的可進(jìn)一步研究。

大整數(shù)的精度丟失

這個問題鮮有人提及。首先得弄清楚問題是什么:

1. JavaScript 能存儲的最大整數(shù)是什么?

該問題前面已回答,是 Number.MAX_VALUE, 非常大的一個數(shù)。

2. JavaScript 能存儲的且不丟失精度的最大整數(shù)是什么?

根據(jù) s x m x 2^e, 符號位取正,52 位尾數(shù)全填充 1, 指數(shù) e 取最大值 971, 顯然,答案依舊是 Number.MAX_VALUE.

我們的問題究竟是什么呢?回到起始代碼:

9999999999999999 == 10000000000000000; // true

很明顯,16 個 9 還遠(yuǎn)遠(yuǎn)小于 308 個 10. 這個問題與 MAX_VALUE 沒什么關(guān)系,還得歸屬到尾數(shù) m 只有 52 位上來。

可以用代碼來描述:

var x = 1; // 為了減少運(yùn)算量,初始值可以設(shè)大一點(diǎn),比如 Math.pow(2, 53) - 10

while(x != x + 1) x++;

// x = 9007199254740992 即 2^53

也就是說,當(dāng) x 小于等于 2^53 時,可以確保 x 的精度不會丟失。當(dāng) x 大于 2^53 時,x 的精度有可能會丟失。比如:

x 為 2^53 + 1 時,其二進(jìn)制表示為:

10000000000...001 (中間共有 52 個 0)

用雙精度浮點(diǎn)數(shù)存儲時:

e = 1; m = 10000..00(共 52 個 0,其中 1 是 hidden bit)

顯然,這和 2^53 的存儲是一樣的。

按照上面的思路可以推出,對于 2^53 + 2, 其二進(jìn)制為 100000…0010(中間 51 個 0),也是可以精確存儲的。

規(guī)律:當(dāng) x 大于 2^53 且二進(jìn)制有效位數(shù)大于 53 位時,就會存在精度丟失。這和小數(shù)的精度丟失本質(zhì)上是一樣的。

hidden bit 可參考:A tutorial about Java double type.

小結(jié)

小數(shù)和大整數(shù)的精度丟失,并不僅僅在 JavaScript 中存在。嚴(yán)格來說,使用了IEEE 754 浮點(diǎn)數(shù)格式來存儲浮點(diǎn)類型的任何編程語言(C/C++/C#/Java 等等)都存在精度丟失問題。在 C#、Java 中,提供了 Decimal、BigDecimal 封裝類來進(jìn)行相應(yīng)的處理,才避開了精度丟失。

注:ECMAScript 規(guī)范中,已有  decimal proposal,但目前尚未被正式采納。

最后考考大家:

Number.MAX_VALUE + 1 == Numer.MAX_VALUE;

Number.MAX_VALUE + 2 == Numer.MAX_VALUE;

...

Number.MAX_VALUE + x == Numer.MAX_VALUE;

Number.MAX_VALUE + x + 1 == Infinity;

...

Number.MAX_VALUE + Number.MAX_VALUE == Infinity;

// 問題:

// 1. x 的值是什么?

// 2. Infinity - Number.MAX_VALUE == x + 1; 是 true 還是 false ?

以上這篇淺談JavaScript中小數(shù)和大整數(shù)的精度丟失就是小編分享給大家的全部內(nèi)容了,希望能給大家一個參考

更多信息請查看網(wǎng)絡(luò)編程
易賢網(wǎng)手機(jī)網(wǎng)站地址:淺談JavaScript中小數(shù)和大整數(shù)的精度丟失
由于各方面情況的不斷調(diào)整與變化,易賢網(wǎng)提供的所有考試信息和咨詢回復(fù)僅供參考,敬請考生以權(quán)威部門公布的正式信息和咨詢?yōu)闇?zhǔn)!

2025國考·省考課程試聽報名

  • 報班類型
  • 姓名
  • 手機(jī)號
  • 驗(yàn)證碼
關(guān)于我們 | 聯(lián)系我們 | 人才招聘 | 網(wǎng)站聲明 | 網(wǎng)站幫助 | 非正式的簡要咨詢 | 簡要咨詢須知 | 新媒體/短視頻平臺 | 手機(jī)站點(diǎn) | 投訴建議
工業(yè)和信息化部備案號:滇ICP備2023014141號-1 云南省教育廳備案號:云教ICP備0901021 滇公網(wǎng)安備53010202001879號 人力資源服務(wù)許可證:(云)人服證字(2023)第0102001523號
云南網(wǎng)警備案專用圖標(biāo)
聯(lián)系電話:0871-65099533/13759567129 獲取招聘考試信息及咨詢關(guān)注公眾號:hfpxwx
咨詢QQ:1093837350(9:00—18:00)版權(quán)所有:易賢網(wǎng)
云南網(wǎng)警報警專用圖標(biāo)