cch
cch
Jan 28, 2018 · 5 min read

在上一次 Data Science — Numpy Basic ! 電子報最後的 reference 有提到 100 numpy exercises ,做到第15題時,遇到了一個浮點數精確度運算的問題:

* 為什麼 0.3 不等於 3 * 0.1 ? 😦

這個就要從機器底層看起,現今機器的 CPU 大多是通過 IEEE-754 標準來執行浮點數運算。簡單來說,IEEE 754 浮點數的組成為符號位 (sign bit)、指數 (exponent)、分數 (fraction) (如下圖)

當你進行浮點數運算時,必須先將數值轉為二進位 :

0.5 = 1/2 (1*2^-1)等於 0.1 (二進位)

0.75 = 1/2 + 1/4 (1*2^-1 + 1*2^-2)等於 0.11 (二進位)

0.875 = 1/2 + 1/4 + 1/8 (1*2^-1 + 1*2^-2 + 1*2^-3)等於 0.111 (二進位)

0.9375 = 1/2 + 1/4 + 1/8 + 1/16 (1*2^-1 + 1*2^-2 + 1*2^-3 + 1*2^-4)等於 0.1111 (二進位)

但如果是 0.1 :

0.1 = 1/16 + 1/32 + 1/256 + 1/512 + … (1*2^-4 + 1*2^-5 + 1*2^-8 + 1*2^-9+…)

無止盡下去的逼近 0.1,但是電腦的記憶體是有限的,因此只能存有限的二進位小數,沒辦法完全等於 0.1,所以 Python 會選擇一個近似值來取代

這裡要記得的是,Python 雖然 print 出來是 0.1,但其實存的是一個逼近 0.1 的二進位分數,電腦沒有辦法精確的存 0.1。

所以我們可以推知很多不同的浮點數 (十進位) 共用同一個二進位分數(0.1, 0.10000000000000001…)

以下兩個例子的等號,會是不相等的。

並且實際上是

那你會想說,那我換成用取四捨五入的方法 ( round( ) ),並且取小數點第一位,這樣應該就可以直接 0.1 + 0.1 + 0.1 = 0.3 了吧 !

很可惜的,還是失敗!

round ( 0.1 , 1 ) 等於 0.1,round( 0.3 , 1 ) 等於 0.3 ,那還是回到原點,0.1 + 0.1 + 0.1 == 0.3 這個算式

0.1 = 1/16 + 1/32 + 1/256 + 1/512 + …

浮點數在做計算時,0.1 不能精確的等於 1/10 ,0.3 不能精確的等於 3/10。

但你可以換個方式:

先進行浮點數的運算,再進行比較,這樣就可以成功的實現比較兩個浮點數。

* 是否真的要精確

一般來說,不建議直接將兩個浮點數進行大小比較,或是我們可以換個角度思考,不要拘泥於完全的相等,讓絕對誤差落在可以接受範圍內,這也是另一個方法。

但除了以下情況,我們非要精確的計算:

  1. 你無法接受一點點的誤差
  2. 你是在進行金融領域的相關計算

我們可以使用 Python Decimal module ( Decimal fixed point and floating point arithmetic ),他可以重現十進位的精準,並且指定小數點位數。

我們可以創建一個 Decimal 物件,傳入參數為 string 。

  1. 數值比較

這樣我們就可以精確的比較浮點數。

注意!這裡如果傳入的參數是 float type ,就無法精準的算出,因為這樣就跟前面所說的一樣,會受到底層存儲 float 的方式,而無法精準的計算。

2. 數值計算

前面說到 Decimal 可以去指定想要取到第幾位小數點,Decimal module default 為取到小數點第28位,我們可以用 getcontext( ) 來查看。

或是去指定欲想要的小數點位數。

getcontext( ) 是去取得 global 的 context ,利用 prec attribute 去指定 global 的小數點位數。如果想指定在某一區段使用特定的小數點位數,自行選擇想要的精準度,可以使用 with statement 以及 context manager

* 總結一下:

Python 使用的浮點數運算方式受到硬體存儲方式所影響,無法精準的算出答案,這時候你可以思考是否使用 Decimal module,但是使用前需要考慮到是否真的需要到如此精準,你的系統會因為小數點17位而受到嚴重的影響嗎?因為原生 Python 所提供浮點數運算相較起來,速度是比較快的,這會影響到在做大資料時運算的速度,所以完全取決於你的應用情形來決定。

Reference:

Decimal — Fixed and floating point math

Floating Point Arithmetic: Issues and Limitations

Python Cookbook, 3rd Edition (3.2 Performing Accurate Decimal Calculations)

浮點數乘法的誤差問題

談浮點數的比較

👏👏👏👏👏👏👏👏👏👏👏👏👏👏👏👏👏👏👏👏👏👏👏👏👏👏

PyLadies Taiwan

Pyladies is an international mentorship group for women who love the Python programming language. https://tw.pyladies.com

cch

Written by

cch

PyLadies Taiwan

Pyladies is an international mentorship group for women who love the Python programming language. https://tw.pyladies.com

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade