Skip to content

Never Store Money in a Float

Never store money in a float means representing monetary amounts with exact units, usually an integer count of the currency’s minor unit plus a currency code, rather than an approximate binary floating-point value. Floats cannot exactly represent many decimal fractions, so arithmetic can leak rounding errors into balances, invoices, and reconciliation.

The problem is that money is not a measurement with acceptable fuzziness. A balance, refund, fee, or tax line normally has to equal another system’s value exactly. Binary floating point is built for approximate numeric work, so common decimal amounts often have no exact representation. The error may be tiny after one operation, but adding, splitting, taxing, converting, serialising, and comparing values can make that hidden approximation visible.

The usual design is a fixed-scale representation. Store the amount as an integer number of minor units and store the currency beside it. For example, a dollar amount is stored as cents, yen is stored as yen because it has no smaller decimal unit, and currencies such as dinar may use a finer minor unit. The application uses currency metadata to decide the scale, then formats the integer for humans at the boundary.

The trade-off is that you must be explicit about scale, currency, rounding, and display. You cannot assume every currency has two decimal places, and the integer alone is meaningless without its currency. Calculations that produce fractional minor units, such as percentage fees or tax apportionment, still need a rounding policy. Exact storage prevents float drift, but it does not answer product or accounting questions for you.

Engineers meet this in database schemas, payment APIs, ledgers, invoice systems, and reconciliation jobs. A typical schema has an amount in minor units and a currency code, sometimes wrapped in a Money type to stop accidental arithmetic across currencies. A common misunderstanding is that rounding a float before saving makes it safe. It does not, because the calculation and transport path may already have used approximate values.

Common questions

Can I use a database decimal type instead of an integer?
It depends on the database, driver, and language boundary. A fixed-precision decimal column can store exact decimal values, but you must ensure the application does not convert them to floats during calculation or serialisation. Integers in minor units are simple, portable, and make the scale decision explicit.
Why is storing the currency code necessary?
The same integer means different things for different currencies. An amount of minor units could represent cents, yen, or a currency with three decimal places. Without the currency code, the application cannot format, validate, round, or compare the value correctly, and cross-currency arithmetic becomes dangerously ambiguous.
Where should rounding happen?
Rounding should happen at defined business boundaries, not accidentally through float behaviour. Examples include calculating tax, allocating a discount, applying a fee, or presenting a final payable amount. The rule depends on the currency, jurisdiction, payment network, and product policy, so make it explicit and test it.