Decimals to 2 places for money in Python 3

后端 未结 5 829
伪装坚强ぢ
伪装坚强ぢ 2020-12-15 05:26

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

相关标签:
5条回答
  • 2020-12-15 05:51

    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)
    
    0 讨论(0)
  • 2020-12-15 05:53

    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.

    0 讨论(0)
  • 2020-12-15 06:00
    >>> 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
    
    0 讨论(0)
  • 2020-12-15 06:02

    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
    
    0 讨论(0)
  • 2020-12-15 06:18

    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.
    0 讨论(0)
提交回复
热议问题