ohmu
ohmu

Reputation: 19780

Decimal rounding with .quantize() does not use original context

If I do the following, I would expect 0.005 to be rounded up to 0.01 instead of down to 0.00 because rounding was set to ROUND_HALF_UP.

>>> import decimal
>>> currency = decimal.Context(rounding=decimal.ROUND_HALF_UP)
>>> cents = decimal.Decimal('0.00')
>>> amount = currency.create_decimal('0.005')
>>> amount
Decimal('0.005')
>>> amount.quantize(cents)
Decimal('0.00')

But if I pass currency to quantize(), it rounds properly:

>>> amount.quantize(cents, context=currency)
Decimal('0.01')

Why does amount (which was created from the currency context) not round using the currency context?

NOTE: This question is not asking how to round to 2 decimal places. I am merely using that as an example. I would like to know why a Decimal created from a Context does not use that same Context when quantizing/rounding.

Upvotes: 2

Views: 4191

Answers (2)

user2357112
user2357112

Reputation: 281843

Decimal objects do not retain the context they were created from. Decimal operations that use a specific context, such as Context.create_decimal or Decimal.quantize with a context argument, only override the global context for that one operation; further operations on the resulting Decimal are done with the global context.

If you want to have all operations use ROUND_HALF_UP, you can set the global context:

decimal.setcontext(currency)

but if you want to mix contexts, you'll have to provide a context explicitly for every operation that needs a context other than the global context.

Upvotes: 6

jermenkoo
jermenkoo

Reputation: 653

You need to set the context using decimal.setcontext() or pass it to quantize() function as a keyword argument to work properly.

>>> import decimal
>>> currency = decimal.Context(rounding=decimal.ROUND_HALF_UP)
>>> decimal.setcontext(currency) # setting the context
>>> cents = decimal.Decimal('0.00')
>>> amount = currency.create_decimal('0.005')
>>> amount.quantize(cents)
Decimal('0.01')

Setting the context globally using decimal.getcontext().rounding = decimal.ROUND_HALF_UP works fine as well, but then it will be use for all future operations with any Decimal.

>>> import decimal
>>> decimal.getcontext().rounding = decimal.ROUND_HALF_UP
>>> cents = decimal.Decimal('0.00')
>>> amount = decimal.Decimal('0.005')
>>> amount.quantize(cents)
Decimal('0.01')

Upvotes: 1

Related Questions