為什麼說浮點數缺乏精確性? python中浮點數運算問題
來源:互聯網
上載者:User
python中的運算為什麼結果接近零而不為零 是什麼原因造成的? 浮點數缺乏精確性應該怎麼解釋? 為什麼前兩個運算式沒出現問題 最後一個出現了問題? 請教
回複內容:
這是因為小數以二進位形式表示時的有窮性導致的。(下面的說法,不完全準確,只是協助理解)
以下是之前我在另一個地方對一個類似問題的解答,因為內容差不多,就直接搬過來了(本人略懶,希望有所協助):
#################################此處開始####################################
我們知道,將一個小數轉化為二進位表示的方式是,不斷的乘2,取其中的整數部分。例如:
+----------------------------------------------------------------------------------------------------------------------------------+
(1) 0.625*2 = 1.25, 整數部分為1,小數部分為0.25
(2) 0.25 * 2 = 0.5 , 整數部分為0,小數部分為0.5
(3) 0.5 * 2 = 1 , 整數部分為1,小數部分為0
+----------------------------------------------------------------------------------------------------------------------------------+
所以0.625的二進位表示就是0.101。
然而有些小數,例如0.4,並不能夠精確的轉化為二進位表示,用上面的這種方法計算:
+----------------------------------------------------------------------------------------------------------------------------------+
(1) 0.4*2=0.8 整數部分為0,小數部分為0.8
(2) 0.8*2=1.6 整數部分為1,小數部分為0.6
(3) 0.6*2=1.2 整數部分為1,小數部分為0.2
(4) 0.2*2=0.4 整數部分為0,小數部分為0.4
(5) 0.4*2=0.8 整數部分為0,小數部分為0.8
(6) 0.8*2=1.6 整數部分為1,小數部分為0.6
(7) 0.6*2=1.2 整數部分為1,小數部分為0.2
……
+----------------------------------------------------------------------------------------------------------------------------------+
所以0.4轉化為二進位,應該是0.0110... 這樣一個無限迴圈小數。
電腦的記憶體、cpu寄存器等等這些硬體單元都是有限的,只能表示有限位元的二進位位,因此儲存的二進位小數就會和實際轉換而成的位元有一定的誤差。(你可以試著將0.3轉化為二進位表示,也將出現一個迴圈小數。)
實際上,大多數情況下,小數在電腦中是以一種類似科學計數法的形式表示的,具體的可以參考一下其他的資料。但即便如此,仍然存在誤差。
所以在python中不建議直接將兩個浮點數進行大小比較,或者做精確的計算,往往會得到意想不到的結果。當然,如果非要用,可以參考decimal模組的相關內容。請將十進位數字0.1轉換成二進位浮點數。這不是Python的問題,而是實數的無限精度跟電腦的有限記憶體之間的矛盾。
舉個例子,假如說我只能使用整數(即只精確到個位,電腦內的浮點數也只有有限精度,以C語言中的雙精確度浮點數double為例,精度為52個二進位位),要表示任意實數(無限精度)的時候我就只能通過舍入(rounding)來近似表示。
比如1.2我會表示成1,2.4表示成2,3.6表示成4.
所以呢?
在算1.2 - 1.2的時候,由於電腦表示的問題,我算的實際上是1 - 1,結果是0,碰巧蒙對了;
在算1.2 + 1.2 - 2.4的時候,由於電腦表示的問題,我算的實際上是1 + 1 - 2,結果是0,再次蒙對了;
但是在算1.2 + 1.2 + 1.2 - 3.6的時候,由於電腦表示的問題,我算的實際上是1 + 1 + 1 - 4,結果是-1,運氣沒那麼好啦!
這裡的1.2, 2.4, 3.6就相當於你問題裡的0.1, 0.2和0.3,1, 2, 4則是真正在電腦內部進行運算的數值,我說清楚了嗎?
其他請看IEEE 754浮點數標準,比如CSAPP第二章啥的(雖然估計你沒興趣看)。
另:不僅僅是浮點數的在電腦內部的表示有誤差,運算本身也可能會有誤差。比如整數2可以在電腦內準確表示,但是要算根號2就有誤差了;再比如兩個浮點數相除,本來兩個數都是精確表示的,但除的結果精度卻超出了電腦內實數的表示範圍,然後就有誤差了。電腦智能處理可數集合的運算,但是全體實數是不可數的,所以電腦只能用一些奇怪的方法來擬合他,於是就產生了浮點數。這個不是python 的問題,所有基於二進位的浮點數都會有這個問題,原因在於大部分浮點數轉換為二進位後都是無限迴圈小數,而浮點數不可能用無限大的記憶體來儲存,所以會有舍入的誤差
詳細可以看代碼之謎(五)來個 @vczh 答案的通俗版,比如用 10 個箱子裝100個球,規定每個箱子只能裝一個球,那顯然是裝不下所有球的。類似,double類型是 64bit 的,最多能表達 2^64 個數,實數有多少呢?無數個,所以 double 類型是裝不下所有實數的,只能表達一個近似值。9.4. decimal電腦所有資訊的儲存使用二進位表示,像 @vczh 所說,有限的「位」,無法表示無數個數,那麼,小數用二進位標記法,只能表示那些能被寫成 的數。
0.1 的二進位表示為 0.000110011[0011]...,因為是無限迴圈的,無法用有限的位表示,所以電腦系統會進行舍入,以求用最接近的值來表示,這裡涉及到不同的舍入方式,具體請見深入理解電腦系統,本答案也是參考該書。大白話版的很多人都說了,就是電腦有限的數字表示不了數學中無窮的數。
樓主如果有一定電腦或者數學基礎可以搜一下IEEE754,電腦是如何表示浮點數的一種協議。看懂了那個協議就知道為什麼了~
如果看不懂IEEE754那就需要研究下數學中各種進位~主要是二進位、十進位和他們的關係。自傲的人類!有本事你直接喂它2進位數,看看還有沒有這種精度問題。