Desk Clarity

A field guide to everyday digital problems.

Developer tools / Practical guide

0.1 Plus 0.2 Differs from 0.3: Choose a Numeric Error Policy

Binary floating-point cannot exactly represent many decimal fractions.

By ON Lab2 min readSources checked November 10, 2026 (KST)

Binary floating-point cannot exactly represent many decimal fractions. Choose a tolerance appropriate to the calculation, or use an exact decimal or integer-unit contract when approximate arithmetic is unsuitable.

Reproduce the behavior safely

Run this self-contained fixture in an empty temporary directory, separate from your project. Shell examples create only named fixture files there. JavaScript examples use local values and send no network requests.

const assert = require('node:assert/strict');
const actual = 0.1 + 0.2;
assert.notEqual(actual, 0.3);
const difference = Math.abs(actual - 0.3);
assert(difference < 1e-12); // Example-specific tolerance, not a universal rule.
const cents = 10 + 20;
assert.equal(cents, 30);
assert(Number.isSafeInteger(cents));
console.log(JSON.stringify({actual, difference, cents}));

Observed local output

{"actual":0.30000000000000004,"difference":5.551115123125783e-17,"cents":30}

Why the result changes

The small difference comes from representing and operating on finite binary approximations. Displaying a rounded string can hide it visually without changing the stored value. The tolerance here was selected for one small example; Number.EPSILON describes spacing near one and is not a universal absolute threshold for all magnitudes or measured inputs. Reassociating a sum can change where rounding occurs, so a+(b+c) need not have identical low bits to (a+b)+c. Parentheses choose an evaluation order; they do not convert the numbers to exact decimals.

Choose and verify the correction

For scientific or measured values, derive absolute and relative tolerances from the domain and input precision. Test near zero as well as large magnitudes. For money in a fixed smallest unit, parse validated decimal text into integer units under an explicit scale and rounding policy, then check safe-integer bounds. Do not assume multiplying an already approximate arbitrary decimal by one hundred is an exact parser. Use a suitable decimal implementation when scale or range requires it.

Limits and next checks

This fixture demonstrates a representation issue and one exact integer sum; it is not financial calculation guidance or a universal approximate-equality function. toFixed produces text and chooses display rounding, not a new exact numeric representation. Separate storage, arithmetic and presentation contracts. Verify negative amounts, rounding ties and accumulation behavior under the policy your application actually uses.

Isolated fixture executed on macOS on November 10, 2026 (KST), with v26.5.0. The observed output verifies this example, not every application or runtime.

Sources & further reading