1、問題
給定一個變量 temp, 變量初始值爲0.1,每次遞增0.1:
let temp = 0.1;
while (temp<10){
temp+=0.1;
console.log(temp)
}
打印值部分序列如下:
0.4>0.5>0.6>0.7>0.799999…>0.899999…>0.9999…>1.09999…>0.9999…>1.09999…>0.99999…
注意到從0.7>0.7999…的部分開始,0.7+0.1=0.7999999999
繼續看以下代碼:
<html>
<script type="text/javascript" >
window.onload =function(){
alert(0.4==0.40000000000000001);//true
}
</script>
</html>
很神奇
大概試了一下,從小數位後18位起,計算機就識別不了了。
2、解釋
典型的精度問題,其實不是我們代碼本身的問題。
計算機是以二進制的方式來存儲數據,代碼中的十進制小數,計算機都會替我們轉換爲二進制去進行計算。
作爲小數,在二進制的情形下,會出現無窮小數的狀況。
舉個例子
十進制15.43轉換成二進制是多少
整數部分:
15%2=1
(15%2)%2=1
((15%2)%2)%2=1
(((15%2)%2)%2)%2=1
除二取餘,逆序排列:1111
小數部分:
Math.ceil(0.43*2)=0
Math.ceil((0.43*2)*2)=1
Math.ceil(((0.43*2)*2)*2)=1
Math.ceil((((0.43*2)*2)*2)*2)=0
Math.ceil(((((0.43*2)*2)*2)*2)*2)=1
Math.ceil((((((0.43*2)*2)*2)*2)*2)*2)……
……
乘二取整,順序排列:01101……
把計算出來的整數部分和小數部分放到一起,中間加上小數點
所以15.43二進制爲:1111.01101……
可以發現,在計算整數部分的過程中,2的0次方=1,這是整數最小單位,二進制整數以"0"或"1"結尾,相應10進制則表現爲奇數或者偶數,涵蓋了所有自然數,所以不會出現無窮序列的情況。
但小數部分如果不正好等於0.5的n次冪,如例子中的0.43,則二進制轉換的這個過程永遠無法結束。
3、解決方案
所以小數的計算,在項目中進行的應用時,不能直接將其交給計算機進行處理,否則大概率會出問題。
人工干預的方法:將小數類型數據轉化成0.5的n次冪家族中的一員,n由項目實際所需的精度而定。