How do I get my decimals to stay at 2 places for representing money using the decimal
module?
I\'ve setting the precision, and damn near everything else
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 * quantity
cents = decimal.Decimal('.01')
money = price.quantize(cents, decimal.ROUND_HALF_UP)
One way to solve this is to store money values in cents as integers, and only convert to decimal representation when printing values. This is called fixed point arithmetic.
>>> decimal.getcontext().prec = 2
>>> d = decimal.Decimal('2.40')
>>> d/17
Decimal('0.14')
You just have to set the precision to 2 (the first line) and them everything will use no more than 2 decimal places
Just for comparison:
>>> 2.4 / 17
0.1411764705882353
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: