DEV Community

Naveen Hooda
Naveen Hooda

Posted on

Why 0.1 + 0.2 breaks your calculator (and how to handle money in JavaScript)

Open your browser console and type:

0.1 + 0.2; // 0.30000000000000004
Enter fullscreen mode Exit fullscreen mode

That's not a JavaScript bug. It's how binary floating point works, and it matters when you're building anything that handles money.

Why it happens

JavaScript numbers are 64-bit binary floats. Just as 1/3 can't be written exactly in decimal, 0.1 can't be written exactly in binary. Tiny errors get stored, and they surface after arithmetic.

Rounding is where it really bites:

(1.005).toFixed(2);          // "1.00"  (you probably expected "1.01")
Math.round(1.005 * 100) / 100; // 1     (same problem)
Enter fullscreen mode Exit fullscreen mode

Fix 1: Use integers for money

Store amounts in the smallest unit, such as paise or cents, as whole numbers.

const priceInPaise = 19999;   // ₹199.99
const total = priceInPaise * 3; // 59997, exact
Enter fullscreen mode Exit fullscreen mode

Convert only when displaying. Integer arithmetic below 2^53 is exact.

Fix 2: Use a decimal library when you need decimals

For things like tax or interest with many digits, libraries like decimal.js or big.js do arithmetic in base 10:

import Decimal from "decimal.js";

new Decimal("0.1").plus("0.2").toString(); // "0.3"
Enter fullscreen mode Exit fullscreen mode

Pass numbers in as strings, otherwise you've already introduced the error.

Fix 3: Round once, at the end

For estimates such as compound interest or SIP projections, floats are usually fine. The rule is: don't round intermediate steps, and round only when you show the result.

const future = 5000 * Math.pow(1 + 0.12 / 12, 12 * 10);
console.log(future.toFixed(2));
Enter fullscreen mode Exit fullscreen mode

Format for humans, not by hand

Don't write your own comma logic. Intl.NumberFormat handles grouping and currency, including the Indian lakh style:

new Intl.NumberFormat("en-IN").format(1234567);
// "12,34,567"

new Intl.NumberFormat("en-IN", { style: "currency", currency: "INR" })
  .format(1234567.5);
// "₹12,34,567.50"
Enter fullscreen mode Exit fullscreen mode

Quick checklist

  • Never compare floats with === after arithmetic
  • Store money as integers or decimal strings
  • Round only for display
  • Use Intl.NumberFormat for formatting
  • Test with awkward values like 1.005, 0.1 + 0.2, and very large amounts

If you want reference numbers to test against, calculators like the compound interest and SIP tools on Erapse (my site) are useful for comparing results.

Have you hit a floating-point bug in production? I'd like to hear about it.

Top comments (0)