Numbers & Math
IEEE-754 double precision 🎯, Special values, Safe integers & precision, BigInt, The Math object
IEEE-754 double precision 🎯#
ELI12. JavaScript stores all regular numbers as 64-bit floating point — like scientific notation in binary. Some decimals (like 0.1) can't be represented exactly in binary, just as 1/3 can't be written exactly in decimal. So tiny errors creep in.
0.1 + 0.2; // 0.30000000000000004 ⚠️
0.1 + 0.2 === 0.3; // false
Math.abs(0.1 + 0.2 - 0.3) < Number.EPSILON; // true — compare with a tolerance
(0.1 + 0.2).toFixed(2); // "0.30" (string)
For money, work in integer cents, or use a decimal library, or BigInt.
Special values#
Infinity; -Infinity; NaN;
1 / 0; // Infinity
-1 / 0; // -Infinity
0 / 0; // NaN
Number.isNaN(NaN); // true 🟢 (global isNaN coerces — avoid)
Number.isFinite(x); // true only for finite numbers
Number.isInteger(5.0); // true
Object.is(NaN, NaN); // true
Object.is(0, -0); // false (only place that distinguishes them)
Safe integers & precision#
Number.MAX_SAFE_INTEGER; // 9007199254740991 (2^53 - 1)
Number.isSafeInteger(2**53); // false — beyond here, integers lose precision
9007199254740993 === 9007199254740992; // true ⚠️ (both round to same double)
BigInt#
const big = 9007199254740993n;
big + 1n; // 9007199254740994n — exact
typeof big; // "bigint"
// ⚠️ cannot mix: 1n + 1 → TypeError; convert explicitly: Number(big) or BigInt(2)
Use BigInt for exact large integers (IDs, cryptography, counters beyond 2^53). No decimals.
The Math object#
Math.round(2.5); // 3 (half-up)
Math.round(-2.5); // -2 ⚠️ (toward +∞, so -2 not -3)
Math.floor(-2.1); // -3
Math.ceil(2.1); // 3
Math.trunc(-2.9); // -2 (drop fraction)
Math.sign(-5); // -1
Math.max(1,2,3); Math.min(...arr);
Math.hypot(3,4); // 5
Math.cbrt(27); // 3
Math.random(); // [0, 1)
// random integer in [min, max]
const randInt = (min, max) => Math.floor(Math.random() * (max - min + 1)) + min;
⚠️ Math.random() is not cryptographically secure — use crypto.getRandomValues() for tokens.
Interview Q&A#
Q1. Why is 0.1 + 0.2 !== 0.3? How do you compare floats safely?
Numbers are IEEE-754 64-bit doubles, and 0.1, 0.2, and 0.3 have no exact binary representation, so the sum lands at 0.30000000000000004. Compare with a tolerance instead of ===: Math.abs(a - b) < Number.EPSILON. For money, use integer cents or a decimal library.
Q2. What's Number.MAX_SAFE_INTEGER and why does it matter? When BigInt?
It's 2^53 - 1 (9007199254740991), the largest integer where every integer up to it is exactly representable; beyond it, integers lose precision (e.g. 9007199254740993 === 9007199254740992). Use BigInt for exact integers past that range — large IDs, counters, cryptography — but it holds no decimals and can't be mixed with Number without an explicit conversion.
Q3. Number.isNaN vs global isNaN? Object.is vs ===?
Number.isNaN returns true only for the actual NaN value; global isNaN coerces its argument first (isNaN("foo") is true), so it's unreliable — avoid it. Object.is behaves like === except it treats NaN as equal to NaN and distinguishes +0 from -0.
Q4. Explain Math.round(-2.5).
It returns -2. Math.round rounds half values toward +Infinity, not away from zero, so -2.5 rounds up to -2 rather than down to -3.