Decimals to 2 places for money in Python 3
When working with money you usually want to limit precision as late as possible so things like multiplication don't aggregate rounding errors. In python 2 and 3 you can .quantize()
a Decimal
to any precision you want:
unit_price = decimal.Decimal('8.0107')quantity = decimal.Decimal('0.056')price = unit_price * quantitycents = decimal.Decimal('.01')money = price.quantize(cents, decimal.ROUND_HALF_UP)
The accepted answer is mostly correct, except for the constant to use for the rounding operation. You should use ROUND_HALF_UP
instead of ROUND_05UP
for currency operations. According to the docs:
decimal.ROUND_HALF_UP
Round to nearest with ties going away from zero.
decimal.ROUND_05UP
Round away from zero if last digit after rounding towards zero would have been 0 or 5; otherwise round towards zero.
Using ROUND_05UP
would only round up (for positive numbers) if the number in the hundredths place was a 5 or 0, which isn't correct for currency math.
Here are some examples:
>>> from decimal import Decimal, ROUND_05UP, ROUND_HALF_UP>>> cents = Decimal('0.01')>>> Decimal('1.995').quantize(cents, ROUND_HALF_UP)Decimal('2.00') # Correct>>> Decimal('1.995').quantize(cents, ROUND_05UP)Decimal('1.99') # Incorrect>>> Decimal('1.001').quantize(cents, ROUND_HALF_UP)Decimal('1.00') # Correct>>> Decimal('1.001').quantize(cents, ROUND_05UP)Decimal('1.01') # Incorrect
Falsehoods programmers believe about money:
- Monetary values can be stored or represented as a floating point.
- All currencies have a decimal precision of 2.
- All ISO 4217 defined currencies have a decimal precision.
- All currencies are defined in ISO 4217.
- Gold is not a currency.
- My system will never have to handle obscure currencies with more than 2 decimal places.
- Floating point values are OK if the monetary value of transactions is "small".
- A system will always handle the same currency (therefore we do not persist the currency, only the monetary value).
- Storing monetary values as signed long integers will make them easier to work with, just multiply them by 100 after all arithmetic is done.
- Customers will never complain about my rounding methods.
- When I convert my application from language X to language Y, I don't have to verify if the rounding behavior is the same.
- On exchanging currency A for currency B, the exchange rate becomes irrelevant after the transaction.