轉(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
現(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)換公式為表示每一位的值為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 。