# 0.1 + 0.2 and someone’s salary

> In a programming contest, an epsilon makes the bug go away. In payroll, an epsilon is a person who got paid one cent less.

- Author: Marcello Oliveira (https://mrcll.me/about/)
- Published: Nov 9, 2026
- Topics: Backend, Fundamentals
- URL: https://mrcll.me/stories/floats-and-salaries/

Here is a program that should print true:

```c
double phi = (1 + sqrt(5)) / 2;
printf(1 / phi == phi - 1 ? "true" : "false");   /* false */
```

The golden ratio satisfies 1/φ = φ − 1 exactly. The computer disagrees in the sixteenth decimal, because the two sides reach the same number through different roundings. In competitive programming the fix is a reflex: compare with a tolerance, `fabs(x - y) < 1e-9`, and move on to the next problem. I did that for years.

To see why, look at what a double actually holds. 0.1 has no exact binary form, so the machine stores the closest value it can.

> Interactive figure (FloatBits): open the web version at https://mrcll.me/stories/floats-and-salaries/

Then the numbers became salaries. Payroll across countries is additions, rates and roundings, millions of times a month, in currencies that do not even agree on how many decimals they have: the Japanese yen has none, the Kuwaiti dinar has three. Every rounding lands in someone’s account, and the totals must reconcile to the last unit. The scenario below is generic, not any company’s system. Add the same amount to a running total, payslip after payslip.

> Interactive figure (PayrollDrift): open the web version at https://mrcll.me/stories/floats-and-salaries/

The drift is a tiny fraction of a cent. Round the total and it even looks right, which is the trap. The equality check fails, the reconciliation job raises an alarm, and someone adds an epsilon to silence it. From then on the epsilon is policy.

## Where the cents really go

The money that actually goes missing comes from somewhere else: applying a rate, an FX conversion or an uplift, and rounding every line.

> Interactive figure (RateRounding): open the web version at https://mrcll.me/stories/floats-and-salaries/

At a rate of 1.15, 2,376 of 100,000 lines round to the wrong cent with floating point. With integer cents and a decimal rate, none do. An epsilon cannot fix that, because nothing is “close enough” about a cent paid to the wrong person.

The fix is a representation, not a comparison:

1. Store money as an integer count of minor units plus a currency, and take the number of decimals from the currency (ISO 4217), never from a global “2”.
2. Do rate math in a decimal type, choose one rounding rule (half-up or half-even), write it down, apply it once at a defined step, and property-test it against exact arithmetic.
3. Treat reconciliation as equality. If totals only match with an epsilon, the bug is upstream.
