Number 的安全范圍
和別的強(qiáng)類型編程語言(比如說 C古掏,Java)不同损话,JavaScript 不區(qū)分整數(shù)值和浮點數(shù)值。
我們可以發(fā)現(xiàn)10 === 10.0 // true
槽唾。那是因為 JavaScript 的數(shù)字類型是基于 IEEE 754 標(biāo)準(zhǔn)中的"雙精度"格式丧枪,也就是 64 位二進(jìn)制來實現(xiàn)的,它是通過如下格式來存儲數(shù)據(jù)庞萍。
符號位(Sign bit): 1 bit(0 表示正數(shù)拧烦, 1 表示負(fù)數(shù))
指數(shù)位(Exponent): 11 bits
有效數(shù)字(Significand precision): 53 bits (52 explicitly stored)在二進(jìn)制中,計算機(jī)內(nèi)部保存有效數(shù)字時钝计,第一個有效數(shù)字必定是1
恋博,因此這個1
并不會存儲齐佳。所以52
位有效數(shù)字可以存儲53
位。
這里可以提到的的一點是:二進(jìn)制浮點數(shù)最大的問題就是在處理0.1 + 0.2
的時候债沮,實際上的結(jié)果不是0.3
炼吴,而是一個比較接近的數(shù)字0.30000000000000004
,這也是因為在它計算的時候,會先轉(zhuǎn)化為二進(jìn)制疫衩,再進(jìn)行計算導(dǎo)致的偏差硅蹦。因為我們在用 JavaScript 或者其他遵循 IEEE 754 規(guī)范的語言處理帶有效數(shù)的數(shù)字時要特別注意。
JavaScript 的數(shù)字格式也就決定了 JavaScript 能夠安全表示的整數(shù)范圍是 -2^53+1 ~ 2^53-1
闷煤。
這里我們可以先明確一下“安全”的概念:
- 可以準(zhǔn)確地表示為一個 IEEE-754 雙精度數(shù)字
- 其 IEEE-754 表示不能是舍入任何其他整數(shù)以適應(yīng) IEEE-754 表示的結(jié)果
比如說:比如童芹,2^53 - 1
是一個安全整數(shù),它能被精確表示鲤拿,在任何 IEEE-754 舍入模式(rounding mode)下假褪,沒有其他整數(shù)舍入結(jié)果為該整數(shù)。作為對比皆愉,2^53
就不是一個安全整數(shù)嗜价,它能夠使用 IEEE-754 表示,但是2^53 + 1
不能使用 IEEE-754 直接表示幕庐,在就近舍入(round-to-nearest)和向零舍入中久锥,會被舍入為2^53
。
可以參考Number.isSafeInteger()的定義异剥。
BigInt 類型
在 ES2020 之前瑟由,JavaScript 只有一種數(shù)值類型:number(數(shù)字),而之后為了安全表達(dá)比 -9007199254740991 ~ 9007199254740991
安全范圍之外的數(shù)字冤寿。引入了BigInt
類型歹苦。
一般計算機(jī)是將整數(shù)存儲在 CPU 的寄存器中(現(xiàn)在通常是 32 位或 64 位寬, JS 是 64bit)督怜,或者存儲在寄存器大小的內(nèi)存塊中殴瘦,這就會帶來安全范圍的問題。而 BigInt 類型為了保證精度号杠。它是在內(nèi)存中分配一個對象蚪腋。我們讓它足夠大,以一系列塊的形式容納所有 BigInt 的位姨蟋,我們稱之為“數(shù)字”
https://v8.dev/blog/bigint
如何使用
- 直接在數(shù)字后面加一個
n
- 調(diào)用
BigInt()
構(gòu)造函數(shù)
const bigInt = 9007199254740992n; //通過直接在數(shù)字后面加n
const bigNumber = BigInt(9007199254740992); // 對十進(jìn)制數(shù)字使用BigInt函數(shù)
const bigString = BigInt("9007199254740992"); //對String類型的使用BigInt函數(shù)屉凯,先隱式轉(zhuǎn)換為十進(jìn)制的數(shù)字,再顯式轉(zhuǎn)換為BigIn類型
const bigHex = BigInt(0x20000000000000); // 對十六進(jìn)制數(shù)字使用BigInt函數(shù)
const bigBin = BigInt(0b100000000000000000000000000000000000000000000000000000); //對二進(jìn)制數(shù)字使用BigInt函數(shù)
以上這些運算生成的值都是9007199254740992n
;
BigInt類型運算
可用操作符
BigInt 中可以運用如下操作符:
符號 | 名稱 |
---|---|
+ | 加法 |
* | 乘法 |
- | 減法 |
% | 求余 |
** | 求冪 |
<< | 左移位 |
>> | 右移位 |
- 當(dāng) BigInt 使用
/
操作符時眼溶,帶小數(shù)的運算會被取整悠砚。
const expected = 4n / 2n; //2n
const rounded = 5n / 2n; //2n, not 2.5n
- 因為 BigInt 都是有符號的,
>>>
(無符號右移)不能用于 BigInt
運算注意事項
BigInt 類型雖然和 Number 很像,可以做各種數(shù)學(xué)運算堂飞,但是在運算過程中要注意兩點:
- BigInt 類型不能用 Math 對象中的方法灌旧。
- 不能和 Number 示例混合運算绑咱。因為 JavaScript 在處理不同類型的運算時,會把他們先轉(zhuǎn)換為同一類型节榜,而 BigInt 類型變量在被隱式轉(zhuǎn)換為 Number 類型時羡玛,可能會丟失精度,或者直接報錯宗苍。
const number = 1;
const bigInt = 9007199254740993n;
number + bigInt; // TypeError: Cannot mix BigInt and other types
BigInt類型和其他類型比較
BigInt 類型的比較和 JavaScript 中的其他類型比較一樣,分為寬松相等和嚴(yán)格相等薄榛。
const bigInt = 2n;
const int = 2;
const string = "2";
bigInt == int; // true
bigInt == string; // true
bigInt === int; // false
bigInt === string; //false