АналитикаСистемный анализСистемный аналитик финансовых интеграций

В финансовой интеграции суммы передаются как числа с плавающей точкой. Какой риск это создаёт при расчёте и...

В финансовой интеграции суммы передаются как числа с плавающей точкой. Какой риск это создаёт при расчёте итогов?

Проходите собеседования с ИИ помощником Hintsage

Краткий ответ

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

Исторический контекст

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

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

Постановка проблемы

Например, значение 0,1 в двоичной системе обычно хранится как ближайшее доступное приближение. При многократном сложении небольшая погрешность накапливается, а сравнение рассчитанного значения с ожидаемым может неожиданно завершиться неравенством.

Риск возникает не только внутри одного сервиса. Один компонент может разобрать JSON-число в двоичный тип, другой — выполнить десятичное округление, а третий — сохранить уже изменённый результат. Это приводит к расхождениям между заказом, оплатой, чеком и бухгалтерской записью.

Подробное решение

На уровне контракта нужно определить:

  • представление суммы — например, целое количество копеек или строка с десятичным значением;
  • валюту и допустимое число знаков после запятой;
  • момент и способ округления;
  • правила для налогов, скидок и комиссий;
  • допустимый диапазон и знак значения.

Целое число в минимальных единицах удобно для валют с фиксированной точностью: 1050 означает 10,50 при масштабе 2. Такой подход исключает дробную часть в вычислениях, но требует хранить масштаб и учитывать валюты с другим количеством десятичных знаков.

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

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

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

Ситуация из практики

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

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

Выбрали второй вариант. Дополнительно зафиксировали правило округления налога и проверку итоговой суммы на границе интеграции. После этого одинаковые входные данные стали давать одинаковые результаты во всех участвующих системах, а расхождения можно было объяснить конкретным бизнес-правилом, а не особенностями представления числа.

Что кандидаты часто упускают

  1. Достаточно ли хранить сумму в целых копейках без указания валюты?

Нет. Число 100 может означать 1,00 в одной валюте и 100 в другой, а некоторые валюты используют другое количество десятичных знаков. Денежная величина должна включать валюту, а масштаб либо следовать из строго определённого справочника валют, либо быть явно закреплён в модели.

  1. Можно ли устранить проблему, сравнивая числа с допустимой погрешностью?

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

  1. Почему одинаковое правило округления всё равно не гарантирует одинаковый итог?

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