Failure Modes Float Drift → Integer Cents

Paid in full.
Still owes $-0.00.

A 30¢ invoice, paid in three 10¢ installments. Computers store 0.1 the same way you'd write 1/3 in decimal: it never divides evenly. Add three of them and you get 0.30000000000000004, not 0.3.

paid $0.00

Naive, sums doubles

invoice
UNPAID
invoice, 30¢ DOUBLE
stored value
total
0
remaining $0.30

Integer cents, sums exactly

invoice
UNPAID
invoice, 30¢ BIGINT
stored value
total
0
remaining $0.30

Pay off the 30¢ invoice in 10¢ installments and watch each system settle it.

How integer money actually works read more

0.1 has no exact binary form, so the computer stores the closest value it can. Every mainstream language works the same way, so they all land on 0.30000000000000004 for three dimes.

The display rounds that away, which is what makes it dangerous: money code checks for an exact zero, not a rounded one. Rounding doesn't fix the drift, it just hides it. Enough payments, and it crosses a real cent.

The fix is the schema, not the arithmetic:

amount DOUBLE               -- 0.1 + 0.1 + 0.1 = 0.30000000000000004

amount_cents BIGINT NOT NULL   -- 10 + 10 + 10 = 30, exactly, forever

Integer cents make every add and compare exact, in any language, in any database. Need real fractions, like an FX rate? DECIMAL is exact too. Floating point is the one that isn't.

The cost: formatting moves to the display layer, and the decimal count depends on the currency (yen has none, Bahraini dinar has three), so the amount has to travel with its currency code.