I'm trying to obtaining a coherent value when formatting a Decimal with '%.2f'. However the results are surprising to me. Same decimal value, different rounding. Any idea what I'm doing wrong ?
>>> from decimal import Decimal
>>> x = Decimal('111.1650')
>>> print '%.2f' % x
111.17
>>> y = Decimal('236.1650')
>>> print '%.2f' % y
236.16
Thank you
Python's percent-style formatting doesn't understand Decimal
objects: when you format, there's an implicit conversion to float. It just so happens that the nearest representable binary float to your x
value is this:
>>> print Decimal(float(x))
111.1650000000000062527760746888816356658935546875
That's a touch greater than the 111.165
halfway case, so it rounds up. Similarly, for y
, the value that ends up being formatted is this one:
>>> print Decimal(float(y))
236.164999999999992041921359486877918243408203125
In that case, the value being formatted for output is just below the halfway value, so it rounds down.
To avoid the implicit conversion, you can use the .format
formatting method:
>>> "{0:.2f}".format(Decimal('111.1650'))
'111.16'
>>> "{0:.2f}".format(Decimal('236.1650'))
'236.16'
Note that you still might not like all the results, though:
>>> "{0:.2f}".format(Decimal('236.1750'))
'236.18'
This style of formatting uses the round-half-to-even rounding mode by default. In fact, it takes the rounding mode from the current Decimal
context, so you can do this:
>>> 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'
As a general comment, being able to implement custom formatting for user-defined classes is one of the big wins for the new-style .format
formatting method over the old-style %
-based formatting.
Your problem is repeatable. As a workaround, you could use the newer libraries.
>>> '{0:.2f}'.format( Decimal('236.1650') )
'236.16'
>>> '{0:.2f}'.format( Decimal('111.1650') )
'111.16'
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With