JS中0.1+0.2為什么不等于0.3

轉(zhuǎn)自:掘金 - 紅塵煉心
https://juejin.cn/post/6927217000112455687

0.1+0.2 的計算過程計算過程

1、十進制轉(zhuǎn)成二進制

在JS內(nèi)部所有的計算都是以二進制方式計算的。 所以運算 0.1+ 0.2 時要先把 0.1和 0.2 從十進制轉(zhuǎn)成二進制。

  • 0.1轉(zhuǎn)化成二進制的算法:

    0.1*2=0.2======取出整數(shù)部分0

    0.2*2=0.4======取出整數(shù)部分0

    0.4*2=0.8======取出整數(shù)部分0

    0.8*2=1.6======取出整數(shù)部分1

    0.6*2=1.2======取出整數(shù)部分1

    接下來會無限循環(huán)

    0.2*2=0.4======取出整數(shù)部分0

    0.4*2=0.8======取出整數(shù)部分0

    0.8*2=1.6======取出整數(shù)部分1

    0.6*2=1.2======取出整數(shù)部分1

    所以0.1轉(zhuǎn)化成二進制是:0.0001 1001 1001 1001......

  • 0.2轉(zhuǎn)化成二進制的算法:

    0.2*2=0.4======取出整數(shù)部分0

    0.4*2=0.8======取出整數(shù)部分0

    0.8*2=1.6======取出整數(shù)部分1

    0.6*2=1.2======取出整數(shù)部分1

    接下來會無限循環(huán)

    0.2*2=0.4======取出整數(shù)部分0

    0.4*2=0.8======取出整數(shù)部分0

    0.8*2=1.6======取出整數(shù)部分1

    0.6*2=1.2======取出整數(shù)部分1

    所以0.2轉(zhuǎn)化成二進制是:0.0011 0011 0011 0011......

這里要注意 0.1 和 0.2 轉(zhuǎn)成的二進制是無窮的。另外在現(xiàn)代瀏覽器中是用浮點數(shù)形式的二進制來存儲二進制,所以還要把上面所轉(zhuǎn)化的二進制轉(zhuǎn)成浮點數(shù)形式的二進制。

2、轉(zhuǎn)成浮點數(shù)

浮點數(shù)分為單精度對應32位操作系統(tǒng)和雙精度對應64位操作系統(tǒng)。目前的操作系統(tǒng)大多是64位操作系統(tǒng),故這里只解釋一下二進制如何轉(zhuǎn)成雙精度浮點數(shù)的二進制。

雙精度浮點數(shù)用1位表示符號位,11位表示指數(shù)位,52位表示小數(shù)位,如下圖所示:

圖片
  • 符號位:正數(shù)為0,負數(shù)為1;

  • 指數(shù)位:階數(shù)+偏移量,階數(shù)是:

    圖片

    e為階碼的位數(shù)。偏移量是把小數(shù)點移動到整數(shù)位只有1時移動的位數(shù),正數(shù)表示向左移,負數(shù)表示向右移;

  • 小數(shù)位:即二進制小數(shù)點后面的數(shù)。

接下來把0.1轉(zhuǎn)成的二進制0.0001100110011001 ......轉(zhuǎn)成浮點數(shù)形式的二進制。

  • 先要把小數(shù)點移動到整數(shù)位只有1,要向右移動4位,故偏移量為?4,通過指位數(shù)的計算公式
    圖片

    把1019轉(zhuǎn)成二進制為1111111011,不夠11位要補零,最終得出指位數(shù)為01111111011;

  • 小數(shù)位為100110011001...... ,因為小數(shù)位只能保留52位,第53位為1故進1。

轉(zhuǎn)換結果如下圖所示:

圖片

同理,再把 0.2 轉(zhuǎn)成的二進制0.0011 0011 0011 0011...... 轉(zhuǎn)成浮點數(shù)形式的二進制,轉(zhuǎn)換結果如下圖所示:

圖片

浮點數(shù)相加

浮點數(shù)相加時,需要先比較指位數(shù)是否一致,如果一致則小數(shù)位直接相加,如果不一致,要先把指位數(shù)調(diào)成一致的,指位數(shù)小的向大的調(diào)整。

為了行文方便,把0.1轉(zhuǎn)成的浮點數(shù)稱為為0.1,把0.2轉(zhuǎn)成的浮點數(shù)稱為0.2。

0.1的指數(shù)位是1019 ,0.2的指數(shù)位是1020 。故要把0.1的指數(shù)位加1,即把0.1的小數(shù)點向左移動1位,另外浮點數(shù)的整數(shù)位固定為1,過程如下所示

1.1001100110011001100110011001100110011001100110011010 原先
0.11001100110011001100110011001100110011001100110011010 移動后
0.1100110011001100110011001100110011001100110011001101 將小數(shù)的第53位舍去,因為為0故不需進1

導致0.1的小數(shù)位變成如下所示:
圖片

現(xiàn)在0.1和0.2的指數(shù)位相同了,把小數(shù)位直接相加。

1100110011001100110011001100110011001100110011001101 0.1的小數(shù)位

  • 1001100110011001100110011001100110011001100110011010 0.2的小數(shù)位
    = 10110011001100110011001100110011001100110011001100111

會發(fā)現(xiàn)現(xiàn)在的小數(shù)位多出了一位,超出了52位,故要把小數(shù)位最后一位截掉,小數(shù)位最后一位是1,故要進1,如下所示:

10110011001100110011001100110011001100110011001100111
1011001100110011001100110011001100110011001100110100

截掉小數(shù)位的最后一位相當把小數(shù)點向左移了一位,故指數(shù)位要加1,此時的指數(shù)是0.2的指數(shù)1021 ,加1后變成1021 ,轉(zhuǎn)成二進制為01111111101 ,那么相加后的浮點數(shù)如下所示:

圖片

浮點數(shù)轉(zhuǎn)成十進制

二進制浮點數(shù)計算結束后,把結果(二進制的浮點數(shù))轉(zhuǎn)成十進制,其轉(zhuǎn)換公式為
圖片

,s是符號位為0或1,e為浮點數(shù)指數(shù)位轉(zhuǎn)成十進制的值,i表示小數(shù)位從左到右的位數(shù),第一位 i=1 ,
圖片

表示每一位的值為0或1。

那么按著公式把二進制的浮點數(shù)轉(zhuǎn)成十進制:

圖片

結果如下所示:

0.3000000000000000444089209850062616169452667236328125

由于精度問題,只取到0.30000000000000004。

答案

0.1+0.2 不等于 0.3 ,因為在 0.1+0.2 的計算過程中發(fā)生了兩次精度丟失。第一次是在 0.1 和 0.2 轉(zhuǎn)成雙精度二進制浮點數(shù)時,由于二進制浮點數(shù)的小數(shù)位只能存儲52位,導致小數(shù)點后第53位的數(shù)要進行為1則進1為0則舍去的操作,從而造成一次精度丟失。第二次在 0.1 和 0.2 轉(zhuǎn)成二進制浮點數(shù)后,二進制浮點數(shù)相加的過程中,小數(shù)位相加導致小數(shù)位多出了一位,又要讓第53位的數(shù)進行為1則進1為0則舍去的操作,又造成一次精度丟失。最終導致 0.1+0.2 不等于0.3 。

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容