如何使用 Python 進行精確的小數計算?


在本文中,我們將學習如何在 Python 中執行精確的小數計算。

使用的方法

  • 使用 decimal 模組的 Decimal() 函式

  • 使用 math 模組的 fsum() 函式

浮點數無法精確表示所有十進位制數是一個眾所周知的缺點。此外,即使是簡單的數學計算也會存在一些誤差。例如 -

示例

以下程式展示了浮點數無法精確表示所有十進位制數 -

x = 4.2
y = 3.1
 
# printing the sum of both the variables
print("x + y =", x + y)
 
# checking if the sum is both the variables is equal to 7.3
print((x + y) == 7.3)

輸出

執行上述程式將生成以下輸出 -

x + y = 7.300000000000001
False

這些錯誤是系統底層 CPU 和其浮點單元使用的 IEEE 754 算術標準的“特性”。如果您使用 float 例項編寫程式碼,則無法防止此類錯誤,因為 Python 的 float 資料型別使用原生表示形式儲存資料。

使用decimal 模組將以犧牲一些效能為代價獲得更高的精度。讓我們在下面看看。

方法 1:使用 decimal 模組的 Decimal() 函式

示例

以下程式展示瞭如何使用 Decimal() 函式進行精確的小數計算 -

# importing Decimal from decimal module
from decimal import Decimal
x = Decimal('4.2')
y = Decimal('3.1')
# printing the sum of both the variables
print("x + y =", x + y)
# checking if the sum is both the variables is equal to 7.3 using by passing the sum to the Decimal Function
print((x + y) == Decimal('7.3'))

輸出

執行上述程式將生成以下輸出 -

x + y = 7.3
True

在上面的程式碼中,一開始看起來可能有點奇怪,即把數字指定為字串。但是,decimal 物件的工作方式完全符合您的預期(支援所有常見的數學運算等)。當您列印它們或在字串格式化函式中使用它們時,它們看起來像普通的數字。

decimal的一個關鍵特性是能夠控制計算的各個方面,例如位數和舍入。

示例

要執行此操作,請建立一個本地上下文並修改其設定。

# importing localcontext from decimal module
from decimal import localcontext
x = Decimal('2.3')
y = Decimal('2.7')
# dividing x by y(returns as a floating-point number)
print(x / y)
with localcontext() as context:
   # rounding the number upto 3 digits i.e, precision 3
   context.prec = 3
   # Dividing x by y with precision set to 3
   print(x / y)

輸出

執行上述程式將生成以下輸出 -

0.8518518518518518518518518519
0.852

將精度值增加到“60”以獲得更高的精度

示例

# importing localcontext from decimal module
import decimal
from decimal import localcontext
x = decimal.Decimal('2.3')
y = decimal.Decimal('2.7')
# dividing x by y(returns as a floating-point number)
print(x / y)
with localcontext() as context:
   # Rounding the number upto 60 digits i.e, precision 60
   context.prec = 60
   # Dividing x by y with precision set to 3
   print(x / y)

輸出

執行上述程式將生成以下輸出 -

0.8518518518518518518518518519
0.851851851851851851851851851851851851851851851851851851851852

方法 2:使用 math 模組的 fsum() 函式

decimal 模組實現了 IBM 的“通用十進位制算術規範”。

不用說,還有很多自定義選項超出了本文的範圍。

Python 初學者可能會傾向於使用 decimal 模組來解決 float 資料型別報告的精度問題。瞭解您的應用領域也很重要。在處理科學或工程問題、計算機圖形或大多數其他科學性質的事物時,使用普通的浮點型別更為常見。

例如,現實世界中相對較少的元素是以浮點數提供的 17 位精度來測量的。因此,即使是微小的計算誤差也沒有影響。原生浮點數的速度也明顯更快,如果您需要執行大量計算,這一點至關重要。

示例

但是,您無法完全避免錯誤。數學家們已經廣泛研究了許多演算法,有些演算法在處理錯誤方面比其他演算法更好。此外,減法抵消和新增大數和小數等實踐帶來的後果需要謹慎處理。

inputList = [1.23e+18, 1, -1.23e+18]

# observe how the 1 disappears here if we perform sum() on the list
print(sum(inputList)) 

輸出

執行上述程式將生成以下輸出 -

0.0

fsum() 查詢給定範圍或可迭代物件之間的總和。它需要匯入 math 庫。它廣泛用於數學計算。

語法

以下是函式的語法。

maths.fsum( iterable )

可迭代物件可以是範圍、陣列或列表。

返回值型別 -

它返回一個浮點數。

示例

以下示例可用於解決math.fsum()中更精確的實現 -

# importing math module 
import math
# input list
inputList = [1.23e+18, 1, -1.23e+18]
# adding the sum of elements of the list using the fsum() function
print(math.fsum(inputList))

輸出

執行上述程式將生成以下輸出 -

1.0

相反,您實際上需要研究並瞭解其他演算法的誤差傳播特性。

儘管如此,處理金融等主題的程式是 decimal 模組最常使用的地方。當此類系統中的計算出現微小的不準確性時,是非常令人不快的。

因此,decimal 模組提供了一種避免這種情況的方法。當 Python 與資料庫互動時,經常會再次遇到 Decimal 物件,尤其是在訪問財務資料時。

結論

在本文中,我們瞭解了普通計算在某些情況下如何失敗以及為什麼需要精確的小數計算。我們學習瞭如何使用兩個不同的函式:decimal() 和 fsum() 執行精確的小數計算。我們還學習瞭如何使用 localcontext() 函式設定結果的精度。

更新於: 2023年1月27日

1K+ 次檢視

開啟你的 職業生涯

透過完成課程獲得認證

開始學習
廣告

© . All rights reserved.