Подтвердить что ты не робот

Десятичные суммы в 2 места за деньги в Python 3

Как мне получить десятичные числа, чтобы остаться в 2 местах для представления денег с помощью модуля decimal?

Я устанавливаю точность и проклинаю почти все остальное, и встречался с ошибкой.

4b9b3361

Ответ 1

При работе с деньгами вы обычно хотите ограничить точность как можно позже, чтобы такие вещи, как умножение, не суммировали ошибки округления. В python 2 и 3 вы можете .quantize() a Decimal выполнить любую требуемую точность:

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

Принятый ответ в основном правильный, за исключением константы, используемой для операции округления. Вы должны использовать ROUND_HALF_UP вместо ROUND_05UP для валютных операций. Согласно docs:

десятичное. ROUND_HALF_UP

      Круглый к ближайшему с увязками, уходящими от нуля.

десятичное. ROUND_05UP

    округление от нуля, если последняя цифра после округления к нулю равна 0 или 5; в противном случае округляется к нулю.

Использование ROUND_05UP будет только округлять (для положительных чисел), если число в сотых местах было равным 5 или 0, что неверно для математической математики.

Вот несколько примеров:

>>> 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

Программисты лживости верят в деньги:

  • Денежные значения могут быть сохранены или представлены как плавающая точка.
  • Все валюты имеют десятичную точность 2.
  • Все идентифицированные валюты ISO 4217 имеют десятичную точность.
  • Все валюты определены в ISO 4217.
  • Золото не является валютой.
  • Моя система никогда не будет обрабатывать неясные валюты с более чем двумя десятичными знаками.
  • Значения с плавающей запятой ОК, если денежная стоимость транзакций "мала".
  • Система всегда будет обрабатывать одну и ту же валюту (поэтому мы не сохраняем валюту, а только денежную стоимость).
  • Сохранение денежных значений, поскольку подписанные длинные целые числа облегчат работу с ними, просто умножьте их на 100 после выполнения всей арифметики.
  • Клиенты никогда не будут жаловаться на мои методы округления.
  • Когда я конвертирую свое приложение из языка X в язык Y, мне не нужно проверять, является ли поведение округления одинаковым.
  • При обмене валюты A на валюту B обменный курс становится неактуальным после транзакции.

Ответ 4

Один из способов решения этой проблемы - хранить денежные значения в центах как целые числа и преобразовывать их только в десятичное представление при печати значений. Это называется арифметикой с фиксированной точкой.

Ответ 5

>>> decimal.getcontext().prec = 2
>>> d = decimal.Decimal('2.40')
>>> d/17
Decimal('0.14')

Вам просто нужно установить точность на 2 (первая строка), и все они будут использовать не более двух знаков после запятой

Просто для сравнения:

>>> 2.4 / 17
0.1411764705882353