Как правильно хранить денежные суммы в программах
Коротко: Деньги никогда не хранят как число с плавающей запятой (float/double), а как целое число в наименьшей единице (центах) или точным десятичным типом.
Подробнее: Двоичные числа с плавающей запятой не могут точно представить многие десятичные дроби. 0.1 + 0.2 в большинстве языков даёт 0.30000000000000004. В суммах такие отклонения накапливаются.
Подробности
- Целые центы: 19,99 € хранится как
1999. Сложение и сравнение точны. Делить на 100 только для отображения. - Десятичные типы:
DECIMAL(12,2)в SQL,BigDecimal(Java),Decimal(Python, C#). Они считают в десятичной системе. - Хранить валюту: Сумма и код валюты (EUR, JPY …) принадлежат друг другу. Не у всех валют два знака после запятой (JPY: 0, KWD: 3).
- Округление: Правило округления задаёт бизнес (коммерческое, банковское) и применяется только в конце цепочек вычислений. Проценты и налоги дают доли цента.
- Разделение: При делении (100 € на 3) остаётся лишний цент, который нужно назначить осознанно.
- Обмен: В JSON передавайте суммы как строку или целые центы, а не как число с десятичными знаками.
См. также: число с плавающей запятой