Блог
Как Boring Expenses хранит деньги (и почему это целое число)
Вот классический способ потерять копейку. Спросите почти любой язык программирования, сколько будет 0.1 + 0.2, и он ответит 0.30000000000000004. Это не баг языка — так устроены двоичные числа с плавающей точкой. Большинство десятичных дробей они не могут представить точно, поэтому вкрадываются крошечные ошибки. Для физики годится; для денег — нет.
Для финансового приложения «примерно» — неправильный ответ. Поэтому Boring Expenses вообще никогда не хранит сумму как дробное число.
Храните наименьшую единицу целым числом
Приём, которым финансовый софт пользуется испокон веков, — работать в наименьших единицах и хранить их целым числом. Вместо $4.20 вы храните 420 — количество центов. Целые числа точны. Складывайте, вычитайте и подводите итоги хоть весь день — никакой пыли от округления не накопится.
Boring Expenses идёт на шаг дальше и хранит суммы в очень мелких дольных единицах (представьте «100 миллионов на одну целую единицу»). Это оставляет большой запас для разных валют и будущих нужд, а всё остаётся обычным Int. Перевод туда и обратно — в то, что вы видите на экране, — происходит на самых краях: когда вы вводите сумму и когда мы её форматируем для показа.
// Иллюстрация, не точный код:
let display = Decimal(amountInSubunits) / Decimal(subunitsPerUnit)
let text = display.formatted(.currency(code: userCurrency))
Почему это важно для вас
- Итоги точны. Ваша сумма за месяц — настоящая сумма, а не число, которое уползает на копейку по мере роста списка.
- Синхронизация согласована. Целое число значит одно и то же на iPhone, на Watch и на iPad. Нечего согласовывать.
- Экспорту можно доверять. CSV, который вы выгружаете, совпадает с приложением до копейки.
Это маленькое, негламурное решение — как раз такие мы любим. Вы его никогда не увидите, и в этом смысл: цифры просто сходятся.