问题
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, and met with failure.
回答1:
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)
回答2:
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
回答3:
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.
回答4:
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.
回答5:
>>> 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
来源:https://stackoverflow.com/questions/7560455/decimals-to-2-places-for-money-in-python-3