精確的小數-decimal初探

精確的小數-decimal初探

2. 精確的小數

二進位可以表示連續的整數,但是卻不能夠表示連續的小數。

在計算機裡面,一個數的小數部分用二進位來表示就是:

s=a_{1}2^{-1}+a_{2}2^{-2}+...+a_{n}2^{-n}

其中 a_{i} 的取值是0或者1。 而a_{1}a_{2}...a_{n} 這個序列就是小數s的二進位編碼。

要得到二進位編碼,可以循環把s乘以2

2s=a_{1}+a_{2}2^{-1}+...+a_{n}2^{-n+1}

因為 a_{1} 是0或者1,所以2s的整數部分就是 a_{1} 。這個時候繼續把小數部分乘以2,整數部分就是 a_{2} 。這樣循環下去就可以得到一個小數的二進位編碼。

用上面的方法來計算0.1的二進位編碼為:

0.0001100110011…

0011這四個編碼可以循環到無數。0.1在二進位編碼裡面,就這樣變成了一個無限循環小數。而計算機是有限存儲的,必然有很多的0011被省略了,因此可以得出一個結論,0.1這個小數是無法在計算機中用二進位編碼精確表示的。

這樣就導致了一個現象。

>>> 0.1+0.20.30000000000000004

使用float類型來存儲小數,兩個小數相加之後居然產生了一個很長的尾巴。

在處理財務數據的過程中,這樣的誤差是不可容忍的。因為即使這樣小的誤差,經過積累後也會產生極大的偏差。必須得有一種數據存儲方式,是使用十進位來存儲的。

Decimal就是專門設計來處理這個問題的。Decimal使用4bits來表示一位小數位數,在存儲上有浪費,但是保證了每一位小數的位數都能按十進位進行存儲。

使用Decimal很簡單,導入decimal模塊之後,就可以構造decimal數進行運算。剛才的代碼,如果用decimal來計算的話,就不會出現錯誤了。

>>>from decimal import *>>>Decimal(0.1)+Decimal(0.2)Decimal(0.3)

2.1 decimal的構造

要使用decimal必須先導入decimal模塊,

>>>from decimal import *

每一個數都需要通過Decimal()進行構造。

可以傳一個整數進去進行構造

>>> Decimal(99)Decimal(99)

可以傳一個字元串進去進行構造

>>> Decimal(0.1)Decimal(0.1)

可以傳一個元組進去進行構造

>>>Decimal((0,(1,1,0),-2))Decimal(1.10)

其中元組第一個參數為符號,0是正號,1是負號;第二個參數(1,1,0)是存儲的數;第三個數-2是指數。

從上面的例子也可以看出,用字元串來構造decimal數是最安全也很容易讀懂。所以推薦傳一個字元串給Decimal構造函數來構造一個decimal數。

這裡要特別指出的是,千萬不要通過不精確的float來構造,因為float為不精確的數,構造的數自然也是不精確的。

>>> Decimal(0.1)Decimal(0.1000000000000000055511151231257827021181583404541015625)

2.2 decimal的運算

decimal數之間可以進行多種基本運算,例如相加,相減,相乘,相除,取絕對值,取冪。

>>>a=Decimal(-0.9)>>>b=Decimal(0.1)>>>a+bDecimal(-0.8)>>> a-bDecimal(-1.0)>>> a*bDecimal(-0.09)>>> a/bDecimal(-9)>>> abs(a)Decimal(0.9)>>> pow(a,2)Decimal(0.81)

decimal數和整型數也可以進行直接的運算

>>> Decimal(0.1)+7Decimal(7.1)>>> Decimal(0.1)*7Decimal(0.7)

decimal和float之間的運算是不允許的,畢竟float並不精確,運算的結果也不會精確。

>>>Decimal(0.1)+0.2Traceback (most recent call last):File "<stdin>", line 1, in <module>TypeError:unsupported operand type(s) for +: Decimal and float

如果只是簡單地利用decimal來實現小數的精確表示以及運算的話,上面兩部分的內容也足夠了。如果需要利用decimal來做更多的精度控制,掌握decimal的數值範圍,以及超過精度之後選用哪一種四捨五入操作,運算過程中如果產生異常需要自行處理等等操作,就需要對decimal有更深的了解。

更深入的內容在下一篇介紹。

本文完

可關注 萬象IT 的微信公眾號,獲得更多資訊。

weixin.qq.com/r/Vijk-Df (二維碼自動識別)


推薦閱讀:

五個非常實用的機器學習資源
c語言的發展歷史如何?
Leetcodes Solutions 7 Reverse Integer
想編程,是勤奮自學還是去培訓班學習?

TAG:Python | 計算機科學 | 編程 |