python中實現(xiàn)精確的浮點數(shù)運算詳解
為什么說浮點數(shù)缺乏精確性?
在開始本文之前,讓我們先來談談浮點數(shù)為什么缺乏精確性的問題,其實這不是Python的問題,而是實數(shù)的無限精度跟計算機的有限內存之間的矛盾。
舉個例子,假如說我只能使用整數(shù)(即只精確到個位,計算機內的浮點數(shù)也只有有限精度,以C語言中的雙精度浮點數(shù)double為例,精度為52個二進制位),要表示任意實數(shù)(無限精度)的時候我就只能通過舍入(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則是真正在計算機內部進行運算的數(shù)值,我說清楚了嗎?
其他請看IEEE 754浮點數(shù)標準,比如CSAPP第二章啥的(雖然估計你沒興趣看)。
另:不僅僅是浮點數(shù)的在計算機內部的表示有誤差,運算本身也可能會有誤差。比如整數(shù)2可以在計算機內準確表示,但是要算根號2就有誤差了;再比如兩個浮點數(shù)相除,本來兩個數(shù)都是精確表示的,但除的結果精度卻超出了計算機內實數(shù)的表示范圍,然后就有誤差了。
好了,下面話不多說了,開始本文的正文:
起步
浮點數(shù)的一個普遍的問題是它們不能精確的表示十進制數(shù)。
>>> a = 4.2 >>> b = 2.1 >>> a + b 6.300000000000001 >>> (a + b) == 6.3 False >>>
這是由于底層 CPU 和IEEE 754 標準通過自己的浮點單位去執(zhí)行算術時的特征??此朴懈F的小數(shù), 在計算機的二進制表示里卻是無窮的。
一般情況下,這一點點的小誤差是允許存在的。如果不能容忍這種誤差(比如金融領域),那么就要考慮用一些途徑來解決這個問題了。
Decimal
使用這個模塊不會出現(xiàn)任何小誤差。
>>> from decimal import Decimal >>> a = Decimal('4.2') >>> b = Decimal('2.1') >>> a + b Decimal('6.3') >>> print(a + b) 6.3 >>> (a + b) == Decimal('6.3') True
盡管代碼看起來比較奇怪,使用字符串來表示數(shù)字,但是 Decimal 支持所有常用的數(shù)學運算。 decimal 模塊允許你控制計算的每一方面,包括數(shù)字位數(shù)和四舍五入。在這樣做之前,需要創(chuàng)建一個臨時上下文環(huán)境來改變這種設定:
>>> from decimal import Decimal, localcontext >>> a = Decimal('1.3') >>> b = Decimal('1.7') >>> print(a / b) 0.7647058823529411764705882353 >>> with localcontext() as ctx: ... ctx.prec = 3 ... print(a / b) ... 0.765 >>> with localcontext() as ctx: ... ctx.prec = 50 ... print(a / b) ... 0.76470588235294117647058823529411764705882352941176 >>>
由于 Decimal 的高精度數(shù)字自然也就用字符串來做展示和中轉。
總結
總的來說,當涉及金融領域時,哪怕是一點小小的誤差在計算過程中都是不允許的。因此 decimal 模塊為解決這類問題提供了方法。
好了,以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。
相關文章
Python continue繼續(xù)循環(huán)用法總結
本篇文章給大家總結了關于Python continue繼續(xù)循環(huán)的相關知識點以及用法,有需要的朋友跟著學習下吧。2018-06-06