[英]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
分數會自動簡化。
有了您的浮動,我認為舍入誤差已經消除只是運氣問題。 請注意,除非您需要絕對精度,否則float
或Decimal
可能就足夠了,在這種情況下,我會推薦Fraction
(例如,這意味着您可以可靠地進行相等測試)。 你總是可以四舍五入一個丑陋的數字,讓它至少看起來更漂亮一點:
In [4]: "{:.2f}".format(Decimal(3) * (Decimal(1) / Decimal(3)))
Out[4]: '1.00'
如果您正在進行模擬之類的操作,則0.9999999
和1
之間的差異通常實際上並不重要。
另一種選擇是重新調整您的操作順序,以便保證分子可以被分母整除,如 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.