Skip to content
All posts

Why 0.1 + 0.2 !== 0.3 (and what to do with money)

IEEE-754 explained in 500 words, why every language does this, and the three correct ways to handle currency.

FDFinance DeskFinance & Numeracy EditorPublished April 26, 20264 min readintermediate

# The famous bug


> 0.1 + 0.2
0.30000000000000004
> 0.1 + 0.2 === 0.3
false

This isn't a JavaScript bug. Python does it. C does it. Go does it. Every language using IEEE-754 doubles — which is every modern language — has this behavior.

# Why it happens

Binary floating point can represent exactly any fraction of the form a / 2ⁿ. It cannot represent 0.1 exactly, because 0.1 in binary is a repeating fraction:


0.1₁₀ = 0.0001100110011001100110011…₂

Just like 1/3 is 0.333… in decimal. Finite digits = rounding error.

A JavaScript number stores 52 bits of mantissa. When you type 0.1, you actually get the number closest to 0.1 that the 52-bit mantissa can represent — which is slightly off. Add two slightly-off numbers, you get a slightly-off sum.

# Why we live with it

Floats trade exactness for speed and range. A double holds numbers from ~10⁻³⁰⁸ to ~10³⁰⁸, fast. Getting exact decimals would require arbitrary-precision arithmetic, which is 100× slower.

For scientific computing, engineering, machine learning — speed wins. For money, you need a different approach.

# Money, done right

# Option 1: Store as integer minor units

$1.23123 cents.


const total = 123 + 456 + 789; // 1368 cents = $13.68
const formatted = (total / 100).toFixed(2); // "13.68"

Integer arithmetic is exact. You only convert to a display string at the UI boundary, never for computation.

Works for any currency. 1 JPY = 1 minor unit. 1 KWD = 1000 minor units (3-decimal currency).

# Option 2: Arbitrary-precision decimals

In JavaScript: BigInt (integer-only), or libraries like decimal.js / dinero.js.


import Decimal from "decimal.js";
new Decimal("0.1").plus("0.2").toString(); // "0.3"

Slower but closer to mathematical intent. Use when you're doing lots of division or percentages.

# Option 3: Don't compound the error

For simple additive arithmetic on a bounded scale (prices in a cart), even floats give correct results if you round at the end:


const total = 19.99 + 4.50 + 2.75;
Math.round(total * 100) / 100; // 27.24

Works until it doesn't. Compound interest over 30 years or iterative divisions — use Option 1 or 2.

# What databases store

  • PostgreSQL: NUMERIC(19,4) is the classic money column. Exact, 19 digits of precision.
  • MySQL: DECIMAL(15,2). Same story.
  • SQLite: no native type; use INTEGER (minor units) or TEXT (string).
  • DynamoDB: Number is string-backed, effectively arbitrary-precision. Safe.

Never use FLOAT or DOUBLE for a money column. Ever.

<div class="callout callout-danger" role="note"><div class="callout-title">Danger</div><div class="callout-body"><p>The single worst bug we've seen in code review: a <code>FLOAT</code> money column summed across 10,000 rows. The rounding errors accumulated to several hundred dollars over a month. The engineer couldn't reproduce it locally because 100 rows didn't drift far enough to notice.</p></div></div>

# What our calculators do

Our Currency Converter, Tip Calculator, VAT Calculator, and other finance tools use JavaScript Number — but round at every step and display with fixed decimal places. For a $1000 tip split 4 ways, this is fine.

If you're writing ledger software, don't imitate us. Use Option 1.

Common questions

Frequently asked.

Is this a JavaScript bug?

No. Every language with IEEE-754 doubles — Python, C, Go, Rust, Java — does the same thing with 0.1 + 0.2. It's not a language flaw; it's the unavoidable cost of representing decimals in binary floating point.

Does this actually matter for my app?

It matters when: (a) you store money as a float, (b) you round at display time and the error accumulates over many rows, (c) you compare floats with `===`. For anything else, it's invisible.

Haftada bir kez yeni gönderiler.

Pratik geliştirici rehberleri. Spam yok. İstediğiniz zaman abonelikten çıkabilirsiniz.

Tools mentioned

Pick up where the post leaves off.

Keep reading

More from the field notes.