Javascript作為一門動態語言,其數字類型只有Number一種。 Nubmer類型使用的就是IEEE754標準中的 雙精度浮點數。Javascript數字的許多特性都依賴于此標準,例如令人費解的0.1+0.2不等于0.3。
這篇文章介紹IEEE754標準中雙精度浮點數二進制儲存格式,并由此推出js中數字的一些特性。
一、IEEE754中浮點數的儲存格式
在IEEE754中,雙精度浮點數儲存為64位:
指數位可以通過下面的方法轉換為使用的指數值:
浮點數表示的值的形式由 和
確定:
二、javascript Number的特性
在js中Number對象上附帶了許多屬性,表示可數的范圍等信息,例如Number.MAX_SAFE_INTEGER
是一個16位的數字,這一部分將解釋如何計算出這些有特殊意義的數字。
1.計算Number.MAX_VALUE和Number.MIN_VALUE
當符號位為0、指數取到1023、小數位全為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
2.計算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,這讓每個小數位都表示浮點數的整數部分,小數位最低位對應 ,然后將每個小數位都置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;
3.計算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