Javascript 做爲一門動態語言,其數字類型只有 number
一種。 nubmer
類型使用的就是 IEEE754 標準中的 雙精度浮點數。Javascript 數字的許多特性都依賴於此標準,例如使人費解的 0.1+0.2不等於0.3javascript
這篇文章介紹 IEEE754 標準中雙精度浮點數二進制儲存格式,並由此推出 js 中數字的一些特性。java
在 IEEE754 中,雙精度浮點數儲存爲64位:安全
指數位能夠經過下面的方法轉換爲使用的指數值:app
浮點數表示的值的形式由 $e$ 和 $f$ 肯定:spa
$0.1 = (0.0\dot0\dot0\dot1\dot1)_2=(-1)^0\times2^{-4}\times(1.\dot1\dot0\dot0\dot1)_2$3d
$0.2 = 0.1\times2^1=(-1)^0\times2^{-3}\times(1.\dot1\dot0\dot0\dot1)_2$code
因爲小數位 $f$ 僅儲存 52bit, 儲存時會將超出精度部分進行"零舍一入"對象
值類型 | 小數位(儲存範圍內) | 小數位(儲存範圍外) |
---|---|---|
無限精確值 | 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 | 1001 1001... |
實際儲存值 | 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1010 | - |
因爲計算加減時不會對指數位進行位運算,這裏不計算指數位的表示,直接使用數字表示最終的指數值blog
0.一、0.2 的表示以下:ip
浮點數數值 | 符號位 $s$ | 指數值 $E$ | 小數位 $f$ |
---|---|---|---|
0.1 | 0 | -4 | 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1010 |
0.2 | 0 | -3 | 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1010 |
在計算浮點數相加時須要先進行「對位」,將較小的指數化爲較大的指數,並將小數部分相應右移
$0.1 \rightarrow (-1)^0\times2^{-3}\times(0.1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1101 0)_2$
$0.2 \rightarrow (-1)^0\times2^{-3}\times(1.1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1010)_2$
$0.1 + 0.2 = (-1)^0\times2^{-2}\times(1.0011001100110011001100110011001100110011001100110100)_2$
能夠經過下面的方法檢驗計算結果是否於 js 中一致:
0.1 + 0.2 === (-1)**0 * 2**-2 * (0b10011001100110011001100110011001100110011001100110100 * 2**-52) //> true //計算正確
在js中 Number對象上附帶了許多屬性,表示可數的範圍等信息,例如 Number.MAX_SAFE_INTEGER
是一個16位的數字,這一部分將解釋如何計算出這些有特殊意義的數字。
Number.MAX_VALUE
和 Number.MIN_VALUE
當符號位爲0、指數取到102三、小數位全爲1時,爲可表示的最大值
當符號位爲0、指數位全爲0(表示非規格浮點數)、小數位僅最後一位爲1時,爲可表示的最小正值
var max = (-1)**0 * 2**1023 * (Number.parseInt( "1".repeat(53) ,2) * 2**-52); max === Number.MAX_VALUE; //> true var min = (-1)**0 * 2**-1022 * (Number.parseInt( "0".repeat(52)+"1" ,2) * 2**-52); min === Number.MIN_VALUE; //> true
Number.MAX_SAFE_INTEGER
和 Number.MIN_SAFE_INTEGER
Number.MAX_SAFE_INTEGER
表示最大安全整數,它是9開頭的16位數字,也代表js number最大精度不超過16位。
ECMASCRIPT-262 定義:
The value of Number.MAX_SAFE_INTEGER is the largest integer n such that n and n + 1 are both exactly representable as a Number value.
http://www.ecma-international...
改變指數位爲53,這讓每一個小數位都表示浮點數的整數部分,小數位最低位對應 $2^0$,而後將每一個小數位都置1,可得最大準確整數:
var max_safe_int = (-1)**0 * 2**52 * (Number.parseInt("1".repeat(53),2) * 2**-52); max_safe_int === Number.MAX_SAFE_INTEGER; //> true //當它 +1 時,可由 (-1)**0 * 2**53 * (Number.parseInt("1"+"0".repeat(52),2) * 2**-52) 正確表示,而再 +1 時則沒法準確表示 //符號位取反可得最小安全整數 -1 * max_safe_int === Number.MIN_SAFE_INTEGER;
Number.EPSILON
Number.EPSILON
是一個極小值,用於檢測計算結果是否在偏差範圍內。例如:
Math.abs(0.1 + 0.2 - 0.3) < Number.EPSILON; //> true //2017-9-27 補充 1.1 + 1.3 - 2.4 < Number.EPSILON //> false
根據 ECMASCRIPT-262 定義:
The value of Number.EPSILON is the difference between 1 and the smallest value greater than 1 that is representable as a Number value, which is approximately 2.2204460492503130808472633361816 x 10−16.
http://www.ecma-international...
根據定義Number.EPSILON
是大於1的最小可表示數與1的差,能夠據此計算出 Number.EPSILON
的值:
//將表示1的二進制小數位的最左端置1,可表示大於1的最小數 var epsilon = (-1)**0 * 2**0 * (Number.parseInt("1"+"0".repeat(51)+"1",2) * 2**-52) - 1; // (-1)**0 * 2**0 * (+`0b1${"0".repeat(51)}1` * 2**-52) - 1; epsilon === Number.EPSILON; //> true