作者| 慕課網精英講師 咚咚嗆
本文首發自「慕課網」,想了解更多IT幹貨内容,程序員圈内熱聞,歡迎關注!
最近有同學在問答區提到了一個很有意思的問題:為什麼0.1 0.2 = 0.30000...4?
這個問題是怎麼來的呢?有Python環境的同學,隻要打開Python終端,輸入0.1 0.2,就能得到0.3000000..4的結果。
那到底這是為什麼?今天就來探讨一下這個問題。
二進制首先我們知道,計算機是以二進制的方式存儲數據的。
比如:5=101(2),15=1111(2),25=11001(2),把十進制轉換成二進制的方式叫做重複相除法,過程大緻是這樣子的。
25/2= 12.....1
12/2=6......0
6/2=3......0
3/2=1......1
1/2=0......1
# 遵循兩個原則
# 1. 重複相除,直到商為0結束
# 2. 餘數結果從下往上得到二進制形式
我們也可以按照按權展開法,得到二進制轉換成十進制的結果,過程大緻是這樣子的。
11001= 1*2^4 1*2^3 1*2^0= 16 8 1= 25。
不過以上隻是整數形式的轉換方法,小數在計算機硬件上也是使用二進制表示的,不過轉換的方法有些不一樣,十進制小數轉換成二進制的方法叫做重複相乘法。
重複相乘法一般來說如果一個小數既有整數部分又有小數部分,那麼這個小數轉換成二進制是分成兩個部分轉換的,整數部分使用重複相除法,小數部分使用重複相乘法。
重複相乘法的大概過程是這個樣子的,比如想把十進制小數0.125轉換成二進制。
0.125*2=0.25=0.25 0
0.25*2=0.5=0.5 0
0.5*2=1=0.0 1
# 注意,這裡把結果分成了小于1和大于等于1的兩個部分,當小于1的部分=0時,結束運算。
# 大于等于1的部分,從上往下得到001即為0.125的小數結果(0.001)。
再舉一個複雜一點的例子:
精度問題
小學我們學過,小數分為有限小數和無限小數,無限小數又分為無限循環小數和無限不循環小數。
同樣的,對于二進制小數來說,同樣有有限小數和無限小數兩大類。那麼重點來了,0.1和0.2在十進制小數裡面是有限小數,但是使用二進制表示的時候就不是了。
不信你使用重複相乘法計算一下試試:
# 運算可以得到:
0.1=0.0001100110011...
# 它實際上是一個無限循環小數
0.1=0.0(0011) # 括号的0011即是無限循環的部分
# 同理得到0.2的二進制
0.2=0.(0011) # 括号的0011即是無限循環的部分
所以計算機是無法準确表示0.1和0.2兩個數的,隻能無限逼近這兩個數。假設計算機使用10位精度,則計算機裡面,0.1和0.2是這樣子的。
0.1=0.0001100110(2)
0.2=0.0011001100(2)
# 現在我們使用二進制加法,運算兩個二進制數
0.0001100110
0.0011001100
————————
0.0100110010(2)
再把這個結果轉換成十進制
0.0100110010(2) = 1*(1/4) 1*(1/32) 1*(1/64) 1*(1/512) = 0.298828125< 3
可以看到這個數值已經很接近3了,如果把精度再調高為16位、32位甚至是64位,會得到更加接近3的結果。這就解釋了為什麼在十進制中運算和在二進制中運算,會得到不一樣的結果。
但是,這就完了嗎?還沒有。其實可以歸納總結到,不管精度是多少,這個結果應該是恒小于3的,而不可能是大于3的結果,因為在截取有效數時,總是把末尾的數值去掉了,那為什麼在Python這裡會大于3呢?
這主要是因為除了精度以外,計算機浮點數表示數據的時候還有對階、零舍一入等等的操作,會使得實際操作數比原操作數大一些。
在十進制中有四舍五入法。比如:
0.499999約等于 0.5
0.41999約等于 0.4
同樣的,在二進制中,有零舍一入的操作。
0.1001(2) 約等于 0.10(2)
0.1011(2) 約等于 0.11(2)
所以在二進制運算中,為了進行有效數值的運算,會對浮點數尾數進行零舍一入的操作,從而導緻真實值和計算值的偏差。
這就可以合理的解釋在Python中0.1 0.2為什麼等于0.3000...4了。
謝謝大家,希望對同學們有所幫助。
歡迎關注「慕課網」,發現更多IT圈優質内容,分享幹貨知識,幫助你成為更好的程序員!
,更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!