IEEE754 浮點數格式 與 Javascript number 的特性

Javascript 做爲一門動態語言,其數字類型只有 number 一種。 nubmer 類型使用的就是 IEEE754 標準中的 雙精度浮點數。Javascript 數字的許多特性都依賴於此標準,例如使人費解的 0.1+0.2不等於0.3javascript

這篇文章介紹 IEEE754 標準中雙精度浮點數二進制儲存格式,並由此推出 js 中數字的一些特性。java

1、IEEE754 中浮點數的儲存格式

在 IEEE754 中,雙精度浮點數儲存爲64位:安全

雙精度浮點數儲存格式

指數位能夠經過下面的方法轉換爲使用的指數值:
指數位表明的值app

浮點數表示的值的形式由 $e$ 和 $f$ 肯定:
浮點數表示的值的形式spa

2、根據 IEEE754 計算 0.1+0.2

1. 將 0.1 使用轉換爲二進制

將 0.1 使用轉換爲二進制

$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

2. 將 0.1 與 0.2 相加

在計算浮點數相加時須要先進行「對位」,將較小的指數化爲較大的指數,並將小數部分相應右移

$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相加

$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
//計算正確

3、計算 javascript Number 的特性

在js中 Number對象上附帶了許多屬性,表示可數的範圍等信息,例如 Number.MAX_SAFE_INTEGER 是一個16位的數字,這一部分將解釋如何計算出這些有特殊意義的數字。

1.計算 Number.MAX_VALUENumber.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

2.計算 Number.MAX_SAFE_INTEGERNumber.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;

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
相關文章
相關標籤/搜索