为什么str()围绕浮动?

时间:2011-04-16 01:30:43

标签: python string rounding

当传入具有许多小数的浮点数时,内置的Python str()函数会输出一些奇怪的结果。这就是:

>>> str(19.9999999999999999)
>>> '20.0'

我期待得到:

>>> '19.9999999999999999'

有谁知道为什么?也许可以解决它?

谢谢!

4 个答案:

答案 0 :(得分:8)

这不是str()轮次,而是你首先使用花车的事实。浮动类型很快,但精度有限;换句话说,他们设计不精确。这适用于所有编程语言。有关浮动怪癖的更多详情,请阅读“What Every Programmer Should Know About Floating-Point Arithmetic

如果您想存储并使用精确数字操作,请使用decimal模块:

>>> from decimal import Decimal
>>> str(Decimal('19.9999999999999999'))
'19.9999999999999999'

答案 1 :(得分:6)

浮点数为32位(至少为C)。其中一个位分配给符号,一些分配给尾数,一些分配给指数。您不能将每个十进制数组合成无限数量的数字到32位。因此,浮点数很大程度上取决于舍入。

如果你试试str(19.998),它可能会给你一些至少接近19.998的东西,因为32位有足够的精度来估计它,但像19.999999999999999这样的东西太精确了,无法估计32位,所以它转向最接近的可能值,恰好是20。

答案 2 :(得分:3)

请注意,这是了解浮点(固定长度)数字的问题。大多数语言与Python的确完全(或非常相似)。

Python floatIEEE 754 64位二进制浮点。它限制在53位精度,即略小于16位精度的十进制数字。 19.9999999999999999包含18位小数;它不能完全表示为floatfloat("19.9999999999999999")生成最近的浮点值,该值恰好与float("20.0")相同。

>>> float("19.9999999999999999") == float("20.0")
True

如果“小数点后”表示“小数点后的多位数字”,请注意在小数点之前有多个小数位时会发生相同的“奇怪”结果:< / p>

>>> 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模块)。

答案 3 :(得分:1)

对于任何给定的二进制浮点数,有一组无限的小数部分,在输入时,舍入到该数字。 Python的str从这个集合产生最短小数部分会遇到麻烦;有关通用算法,请参阅GLS的论文http://kurtstephens.com/files/p372-steele.pdf(IIRC,他们使用了一种在大多数情况下避免任意精度数学的细化)。您碰巧输入了一个小数部分,该小数部分舍入为浮点数(IEEE double),其最小可能小数与您输入的小数位数不同。