Москва: проверенные б/у ноутбуки с гарантией и проверкой перед оплатой
+7 906 722-94-45

Главная → Статьи → Округление денежных значений

Округление денежных значений: правила и порядок применения

Округление денег: режимы округления, округление banker's rounding, порядок применения в расчёте и распределение остатка по позициям.

Прямой ответ

Округление приводит значение к разряду валюты по фиксированному правилу, поэтому итог расчёта совпадает между позициями и не расходится с отчётностью.

Режим округления Что делает
HALF_UP Округляет половину вверх
HALF_EVEN Округляет половину к чётному
FLOOR Отбрасывает дробную часть вниз
CEILING Округляет вверх к ближайшему
from decimal import Decimal, ROUND_HALF_UP

value = Decimal("10.125")
value.quantize(Decimal("0.01"), rounding=ROUND_HALF_UP)   # Decimal("10.13")

Округление выполняется после полного вычисления, поэтому промежуточные значения сохраняют точность и не накапливают погрешность. О типах — в статье про Decimal против float.

Режимы округления и выбор правила

Режим округления определяет, куда приводится значение на границе разряда, поэтому выбор режима влияет на итог расчёта.

Округление половины вверх. Значение на границе разряда округляется в большую сторону, поэтому режим соответствует привычному правилу округления.

Округление половины к чётному. Значение на границе разряда округляется к ближайшему чётному, поэтому смещение при большом числе операций уменьшается.

Отбрасывание и округление вверх. Значение приводится вниз либо вверх независимо от величины дробной части, поэтому режим применяется по требованию расчёта.

Практическое следствие: режим округления, не зафиксированный в коде, применяется по умолчанию среды выполнения, поэтому результат отличается между системами.

Отдельный аспект — округление половины к чётному. Режим уменьшает систематическое смещение при большом числе операций, поскольку половина значений округляется вниз, а половина вверх. Режим применяется в финансовых расчётах, где накопление смещения в одну сторону недопустимо.

Порядок применения округления

Порядок округления определяет, применяется ли правило к промежуточным значениям либо только к итогу, поэтому результат различается.

Округление после расчёта. Промежуточные значения сохраняют полную точность, поэтому округление применяется один раз к итоговому значению.

Округление на каждом шаге. Каждое промежуточное значение приводится к разряду, поэтому итог накапливает расхождение от округления.

Различие итога. Итог при округлении на каждом шаге отличается от итога при округлении после расчёта, поэтому правило фиксируется явно.

Практическое следствие: расчёт, округляющий промежуточные значения, даёт итог, расходящийся с расчётом, округляющим только результат, поэтому сверка показывает расхождение.

Распределение остатка по позициям

Деление суммы на части даёт дробные значения, поэтому округление частей приводит к расхождению суммы частей с исходной суммой.

Дробные части. Деление суммы на равные части даёт значения с дробной частью, поэтому каждая часть округляется до разряда валюты.

Расхождение суммы. Сумма округлённых частей отличается от исходной суммы на несколько разменных единиц, поэтому расхождение требует распределения.

Распределение остатка. Остаток добавляется к части позиций, поэтому сумма частей совпадает с исходной суммой.

Практическое следствие: сумма округлённых частей, не приведённая к исходной сумме, расходится с ней, поэтому расчёт не сходится при проверке.

О хранении денежных значений — в статье про деньги в приложении; о расчёте налогов — в статье про расчёт НДС.

Практика: настройка округления

1. Фиксируйте режим округления в коде. Режим применяется единообразно, поэтому результат не зависит от среды выполнения.

2. Округляйте после полного вычисления. Промежуточные значения сохраняют точность, поэтому итог не накапливает расхождение.

3. Используйте округление половины к чётному для массовых расчётов. Смещение при большом числе операций уменьшается.

4. Указывайте разряд валюты явно. Число знаков после запятой определяется минимальной единицей валюты.

5. Распределяйте остаток при делении суммы на части. Сумма частей совпадает с исходной суммой, поэтому расхождение исключается.

6. Проверяйте сумму частей против исходной суммы. Расхождение указывает на нераспределённый остаток.

7. Применяйте единое правило во всех расчётах. Разные правила в разных местах приводят к расхождению итогов.

Рекомендации:

  1. Не полагайтесь на режим округления по умолчанию. Режим среды выполнения может отличаться, поэтому результат не воспроизводится.
  2. Учитывайте расхождение при округлении на каждом шаге. Итог отличается от округления после расчёта, поэтому правило фиксируется.
  3. Сопоставляйте режим с требованием расчёта. Округление половины к чётному уменьшает смещение, округление вверх соответствует привычному правилу.
  4. Фиксируйте разряд валюты в схеме. Разрядность должна покрывать минимальную единицу валюты.
  5. Пересматриваем правило при добавлении валюты. Новая валюта может иметь иное число разменных единиц.

Практический сценарий: сумма частей не совпадала с исходной суммой

Контекст: сумма заказа распределялась между позициями, но сумма позиций отличалась от суммы заказа на одну копейку.

  1. Диагностика. Проверка показала, что деление суммы на число позиций давало значение с дробной частью. Каждая позиция округлялась до копеек, поэтому сумма округлённых позиций отличалась от исходной суммы.
  2. Причина. Остаток от деления не распределялся между позициями, поэтому округление каждой части приводило к потере разменной единицы.
  3. Действия. (а) Вычислили сумму округлённых позиций и сравнили с исходной суммой, чтобы определить остаток; (б) распределили остаток по первым позициям, чтобы сумма частей совпала с исходной суммой; (в) зафиксировали режим округления явно, чтобы правило не зависело от среды выполнения; (г) перенесли округление в конец расчёта каждой позиции, чтобы промежуточные значения сохраняли точность; (д) добавили проверку суммы позиций против суммы заказа, чтобы расхождение обнаруживалось.
  4. Результат. Сумма позиций совпадает с суммой заказа, поскольку остаток распределяется между позициями.

Вывод: деление суммы на части с последующим округлением даёт сумму частей, отличающуюся от исходной суммы на величину остатка. Распределение остатка по позициям и проверка суммы частей устраняют расхождение.

FAQ

Какой режим округления выбрать для денег? Фиксированный в коде. Округление половины к чётному уменьшает смещение при массовых расчётах, округление половины вверх соответствует привычному правилу.

Когда выполнять округление в расчёте? После полного вычисления. Округление на каждом шаге накапливает расхождение и даёт иной итог.

Почему сумма частей не совпадает с исходной суммой? Остаток от деления не распределяется между частями, поэтому округление каждой части приводит к потере разменных единиц.

Зачем фиксировать режим округления в коде? Режим по умолчанию зависит от среды выполнения, поэтому результат не воспроизводится между системами.

Источники: Python decimal, PostgreSQL math functions, PostgreSQL numeric types — ссылки в шапке.