簡體   English   中英

Python Decimal 給出了錯誤的結果

[英]Python Decimal gives incorrect result

我在進行以下計算時遇到問題:

Decimal(3)*(Decimal(1)/Decimal(3))

它不是返回 1.0,而是返回 0.999...

無論我將Decimal模塊的精度提高多少,情況仍然如此。

這是完整的代碼:

from decimal import Decimal
from decimal import getcontext
getcontext().prec = 800
print Decimal(3)*(Decimal(1)/Decimal(3))

具有諷刺意味的是,使用“原生” float解決了這個問題:

print float(3)*(float(1)/float(3))

不用說,我在這里使用Decimal進行更復雜的計算,涉及大數的取冪。 遇到這個問題后,我設法將其最小化為上面的示例。

稍微擴展一下我的評論:

Python 中的十進制數實際上就是您可以手寫的那種數字。 重要的是,它不理解遞歸的概念,所以像1 / 3這樣無限循環的分數只是表示為0.333333333333..直到你的精度點。 當它乘以 3 時,您會得到0.99999.. - 這是明智的行為,因為它實際上無法知道0.33333333..在被截斷后是1 / 3 Decimal經常因除法時的舍入而失去精度(實際上,除以除 2 或 5 以外的任何因子時)。 如果能夠進行除法至關重要,請使用Fraction ,它表示任何有理數而不會損失分子和分母的任何精度:

In [1]: from fractions import Fraction

In [2]: Fraction(3) * Fraction(1, 3)
Out[2]: Fraction(1, 1)

In [3]: print(_)
1

分數會自動簡化。

有了您的浮動,我認為舍入誤差已經消除只是運氣問題。 請注意,除非您需要絕對精度,否則floatDecimal可能就足夠了,在這種情況下,我會推薦Fraction (例如,這意味着您可以可靠地進行相等測試)。 你總是可以四舍五入一個丑陋的數字,讓它至少看起來更漂亮一點:

In [4]: "{:.2f}".format(Decimal(3) * (Decimal(1) / Decimal(3)))
Out[4]: '1.00'

如果您正在進行模擬之類的操作,則0.99999991之間的差異通常實際上並不重要。

另一種選擇是重新調整您的操作順序,以便保證分子可以被分母整除,如 Anilkumar 的回答所示。 如果可能,這是一個很好的解決方案,但在某些情況下您可能無法這樣做 - 例如,您期望結果是小數,或者您從某種黑匣子中獲得小數被乘數。 在這一點上,可以同時跟蹤Decimal分子和分母......然后您意識到這就是Fraction類所做的,但麻煩更少。

請注意,您可以將Fraction用於Decimal可以做的任何事情,但更重要的是。 任何可表示的十進制數也是分數(10 的某個冪的尾數)。 例如:

In [2]: Fraction("3.141")
Out[2]: Fraction(3141, 1000)

自然,這會導致一些性能損失 - 分數必須跟蹤更多數據,進行更多計算並且可能更抽象一些。

查看您新提供的公式 - 請注意,當您將有理數提高到非整數的冪時,結果可能不是有理數,因此您可能會在途中的某處丟失分數,例如:

>>> Fraction(1, 2) ** 4
Fraction(1, 16)
>>> Fraction(1, 2) ** 0.5
0.7071067811865476

盡管在評估公式的上下文中,嘗試以符號方式存儲所有內容並沒有多大意義。 這讓我們回到了粗略float通常已經足夠好的想法。 如果你真的想要某種 surd 輸出格式,你可以給sympy一個機會:

In [1]: from sympy import *

In [2]: sqrt(Integer(1) / Integer(2))
Out[2]: sqrt(2)/2

這當然會讓你更慢。

我認為要改變括號:

from decimal import Decimal
from decimal import getcontext
getcontext().prec = 800
print (Decimal(3)*Decimal(1))/Decimal(3)

對我來說,輸出為 1 以上

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM