如果你問一個小學生 0.1+0.2等于多少,我相信他會毫不猶豫地告訴你等于0.3,但是如果你去問一個程式員,他就會很謹慎地告訴你,稍等一下,然后飛快地在電腦上敲下幾行代碼:
public class Demo {
public static void main(String[] args) {
System.out.println(0.1 + 0.2);
}
}
這時候你心里肯定在說:”這哥們小學沒畢業?這種問題還要用電腦算?“ 就在你即將不屑地轉身離開時,電腦上出現了計算結果:
0.30000000000000004
”什么鬼?我讀書少你別騙我,一定是電腦壞了!“

OK,電腦沒有壞,那強大的電腦和聰明絕頂的程式員為什么比不上一個小學生呢?我們來一起分析一下:
首先我們來復習一下義務教育階段學習的一個重要知識點:科學計數法
把一個數表示成a與10的n次冪相乘的形式(1≤|a|<10,n為整數)
我們都知道計算機中的資料都是以二進制形式來表示的,在記憶體中有兩種存盤方式:
float(單精度)1位符號位8位指數位23位尾數位
double(雙精度)1位符號位11位指數位52位尾數位
首先將十進制0.1轉換為二進制,十進制小數轉二進制一般采用乘2取整法:
0.1 x 2 = 0.2 整數部分為 0 小數部分繼續 x 2
0.2 x 2 = 0.4 整數部分為 0 小數部分繼續 x 2
0.4 x 2 = 0.8 整數部分為 0 小數部分繼續 x 2
0.8 x 2 = 1.6 整數部分為 1 小數部分繼續 x 2
0.6 x 2 = 1.2 整數部分為 1 小數部分繼續 x 2
0.2 x 2= 0.4 整數部分為 0 小數部分繼續 x 2
...

重復計算得到64位二進制小數:
0.0001100110011001100110011001100110011001100110011001100110011001
以二進制科學計數法來表示,也就是a與2的n次冪相乘的形式(1≤|a|<2,n為整數),a就是尾數,n就是指數,即
1. 100110011001100110011001100110011001100110011001100110011001 * 2 ^ -4
先來處理尾數,JAVA浮點數默認為雙精度,使用52位存盤尾數,由于二進制的科學計數法整數位永遠都是1,因此可以直接不存盤,截取小數部分前52位為尾數位(0舍1入)
1001100110011001100110011001100110011001100110011010
再來處理指數,由于指數位為11位,因此指數偏移值為2 ^ 10 -1 = 1023, 指數位實際值 x - 1023 = -4, 得到x為1019,轉為二進制1111111011, 高位補0,滿11位,得01111111011
正數符號位為0,得到0.1的雙精度二進制表示為:
0 01111111011 (1.)1001100110011001100110011001100110011001100110011010
同理,得到0.2的雙精度二進制表示為:
0 01111111100 (1.)1001100110011001100110011001100110011001100110011010
在相加之前將0.1的指數調整和0.2的指數相同(即-4調為-3),同時將尾數右移一位得到(0.)11001100110011001100110011001100110011001100110011010,根據0舍1入原則將最后一位0舍去得到
0 01111111100 (0.)1100110011001100110011001100110011001100110011001101

現在可以將尾數相加了:
0.1100110011001100110011001100110011001100110011001101
+ 1.1001100110011001100110011001100110011001100110011010
10.0110011001100110011001100110011001100110011001100111
尾數計算結果規格化處理,向右移一位(最后一位1舍去),同時將指數+1得到雙精度計算結果
0 01111111101 (1.) 0011001100110011001100110011001100110011001100110011(1)
由于右規了一位1,因此需要進行+1預算
0011001100110011001100110011001100110011001100110011
+ 0000000000000000000000000000000000000000000000000001
0011001100110011001100110011001100110011001100110100
最終得到的結果為:
0 01111111101 0011001100110011001100110011001100110011001100110100
轉為10進制為:

0.30000000000000004440892098500626
這就是0.1+0.2不等于0.3的原因所在,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/222244.html
標籤:其他
下一篇:WordCount專案基本功能
