Python十进制格式错误的行为?

时间:2013-08-01 17:54:53

标签: python decimal rounding number-formatting

我在尝试使用'%。2f'格式化Decimal时尝试获取连贯值。然而,结果令我感到惊讶。相同的十进制值,不同的舍入。知道我做错了吗?

>>> from decimal import Decimal
>>> x = Decimal('111.1650')
>>> print '%.2f' % x
111.17
>>> y = Decimal('236.1650')
>>> print '%.2f' % y
236.16

谢谢

3 个答案:

答案 0 :(得分:5)

Python的百分比样式格式化不理解Decimal个对象:格式化时,隐式转换为float。恰好,最接近可表示的二进制浮点数为x值为:

>>> print Decimal(float(x))
111.1650000000000062527760746888816356658935546875

这比111.165中途的情况要大,所以它会向上舍入。同样,对于y,最终格式化的值是这一个:

>>> print Decimal(float(y))
236.164999999999992041921359486877918243408203125

在这种情况下,为输出格式化的值恰好低于中间值,因此它向下舍入。

要避免隐式转换,您可以使用.format格式化方法:

>>> "{0:.2f}".format(Decimal('111.1650'))
'111.16'
>>> "{0:.2f}".format(Decimal('236.1650'))
'236.16'

请注意,您仍然可能不喜欢所有结果:

>>> "{0:.2f}".format(Decimal('236.1750'))
'236.18'

默认情况下,这种格式化使用舍入到半舍入到舍入模式。实际上,它采用当前Decimal上下文的舍入模式,因此您可以执行此操作:

>>> from decimal import getcontext, ROUND_HALF_UP
>>> getcontext().rounding=ROUND_HALF_UP
>>> "{0:.2f}".format(Decimal('236.1750'))
'236.18'
>>> "{0:.2f}".format(Decimal('236.1650'))  # Now rounds up!
'236.17'

作为一般性评论,能够为用户定义的类实现自定义格式是新式.format格式化方法相对于基于旧式%的格式化的重大胜利之一

答案 1 :(得分:3)

您的问题是可重复的。作为解决方法,您可以使用较新的库。

    >>> '{0:.2f}'.format( Decimal('236.1650') )
    '236.16'
    >>> '{0:.2f}'.format( Decimal('111.1650') )
    '111.16'

答案 2 :(得分:2)

这是因为无法准确表示浮点值。请参阅文档floating point arithmetic.

或者,为了告诉您发生了什么,请输入:

>>> Decimal(111.1650)
Decimal('111.1650000000000062527760746888816356658935546875')
>>> Decimal(236.1650)
Decimal('236.164999999999992041921359486877918243408203125')

问题是在您的情况下浮点数不准确接近.005边界。你刚刚遇到这样的情况:一个数字略高于.005(因此被剔除)而另一个数字略低于下面并被淹没。