Blog

How Boring Expenses stores money (and why it's an integer)

  • engineering
  • ios
  • swift

Here’s a classic way to lose a cent. Ask almost any programming language what 0.1 + 0.2 equals and it will tell you 0.30000000000000004. That’s not a bug in the language — it’s how binary floating-point numbers work. They can’t represent most decimal fractions exactly, so tiny errors creep in. Fine for physics; not fine for money.

For a finance app, “close enough” is the wrong answer. So Boring Expenses never stores an amount as a decimal at all.

Store the smallest unit as a whole number

The trick money software has used forever is to work in the smallest unit and keep it as an integer. Instead of $4.20, you store 420 — the number of cents. Integers are exact. Add, subtract, and total them all day and you never accumulate rounding dust.

Boring Expenses takes this a step further and stores amounts in very fine sub-units (think “100 million per whole unit”), which leaves plenty of headroom for currencies and future needs while keeping everything as a plain Int. Conversion to and from what you actually see on screen happens at the very edges — when you type an amount in, and when we format one out.

// Illustration, not the exact code:
let display = Decimal(amountInSubunits) / Decimal(subunitsPerUnit)
let text = display.formatted(.currency(code: userCurrency))

Why this matters for you

It’s a small, unglamorous decision — exactly the kind we like. You’ll never see it, and that’s the point: the numbers just add up.