![](/img/trans.png)
[英]Why does round raise on ndigits=None for integers but not for floats?
[英]Why does str() round up floats?
當傳入具有許多小數的浮點數時,內置的Python str()函數會輸出一些奇怪的結果。 這是發生的事情:
>>> str(19.9999999999999999)
>>> '20.0'
我期待得到:
>>> '19.9999999999999999'
有誰知道為什么? 也許可以解決它?
謝謝!
這不是str()
,而是你首先使用花車的事實。 浮動類型很快,但精度有限; 換句話說,它們在設計上是不精確的 。 這適用於所有編程語言。 有關浮動怪癖的更多詳細信息,請閱讀“ 每個程序員應該知道的關於浮點算術的內容 ”
如果要存儲和操作精確數字,請使用decimal
模塊:
>>> from decimal import Decimal
>>> str(Decimal('19.9999999999999999'))
'19.9999999999999999'
浮點數為32位(至少為C)。 其中一個位分配給符號,一些分配給尾數,一些分配給指數。 您不能將每個十進制數組合成無限數量的數字到32位。 因此,浮點數很大程度上取決於舍入。
如果你嘗試str(19.998)
,它可能會給你一些至少接近19.998的東西,因為32位具有足夠的精度來估計它,但像19.999999999999999這樣的東西太精確而不能用32位估計,所以它舍入到最接近的可能值,恰好是20歲。
請注意,這是了解浮點(固定長度)數字的問題。 大多數語言與Python的確完全(或非常相似)。
Python float
是IEEE 754 64位二進制浮點數。 它僅限於53位精度,即略低於16位精度的十進制數字。 19.9999999999999999
包含18位小數; 它不能完全表示為float
。 float("19.9999999999999999")
生成最近的浮點值,該值恰好與float("20.0")
。
>>> float("19.9999999999999999") == float("20.0")
True
如果用“多個小數”表示“小數點后的多位數”,請注意當小數點前有多個十進制數字時,會發生相同的“奇怪”結果:
>>> float("199999999999999999")
2e+17
如果你想要完整的float
精度,不要使用str(),使用repr():
>>> x = 1. / 3.
>>> str(x)
'0.333333333333'
>>> str(x).count('3')
12
>>> repr(x)
'0.3333333333333333'
>>> repr(x).count('3')
16
>>>
更新有趣的是, decimal
經常被規定為一個治愈浮動引起的驚訝的全部治療方法。 這通常伴隨着簡單的例子,如0.1 + 0.1 + 0.1 != 0.3
。 沒有人停下來指出decimal
有其不足之處,例如
>>> (1.0 / 3.0) * 3.0
1.0
>>> (Decimal('1.0') / Decimal('3.0')) * Decimal('3.0')
Decimal('0.9999999999999999999999999999')
>>>
是的, float
限制為53位精度的二進制數字。 默認情況下, decimal
限制為精度的28位十進制數字。
>>> Decimal(2) / Decimal(3)
Decimal('0.6666666666666666666666666667')
>>>
您可以更改限制 ,但它仍然是有限的精度。 您仍然需要知道數字格式的特征才能有效地使用它而不會產生“驚人”的結果,並且通過較慢的操作來獲得額外的精度(除非您使用第三方cdecimal
模塊)。
對於任何給定的二進制浮點數,有一組無限的小數部分,在輸入時,舍入到該數字。 Python的str
從這個集合產生最短的小數部分會遇到一些麻煩; 有關通用算法,請參閱GLS的論文http://kurtstephens.com/files/p372-steele.pdf(IIRC他們使用一種在大多數情況下避免任意精度數學的細化)。 您碰巧輸入了一個小數部分,該小數部分舍入為浮點數(IEEE double),其最小可能小數與您輸入的小數位數不同。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.