JavaScriptNumbers

Numbers

JavaScript famously has one number type. Whether you write 42, 3.14, -7 or 1e9, the engine stores them all the same way — as 64-bit double-precision floating-point values, the format defined by the IEEE 754 standard. That single decision shapes most of the quirks you'll meet on this page: limited precision, weird edge cases like NaN and Infinity, and the existence of a separate BigInt type for when 64 bits aren't enough.

One type to rule them all

There is no int, float, double or long in JavaScript. The typeof of every number — integer or not — is just "number".

JS
console.log(typeof 42);        // "number"
console.log(typeof 3.14);      // "number"
console.log(typeof -0);        // "number"
console.log(typeof NaN);       // "number"
console.log(typeof Infinity);  // "number"
number
number
number
number
number
How numbers are stored (IEEE 754)

A 64-bit double splits into one sign bit, eleven exponent bits and fifty-two fraction bits. The practical implications:

  • Integers are exact up to 2^53 − 1 (Number.MAX_SAFE_INTEGER, 9,007,199,254,740,991). Beyond that, integers start skipping values.

  • Fractional numbers in base 10 often have no exact binary representation — the same way 1/3 has no exact decimal representation.

  • The largest representable value is Number.MAX_VALUE (~1.79e308). Anything bigger becomes Infinity.

  • The smallest positive value is Number.MIN_VALUE (~5e-324). Smaller magnitudes underflow to 0.

Number literals

You can write the same value in several ways depending on the base or the readability you want:

JS
const dec  = 255;            // decimal
const hex  = 0xff;           // hexadecimal — also 255
const bin  = 0b1111_1111;    // binary — also 255
const oct  = 0o377;          // octal — also 255
const big  = 1_000_000;      // numeric separators are just visual
const sci  = 6.022e23;       // scientific notation
const tiny = 1.6e-19;        // small numbers too

console.log(dec === hex && hex === bin && bin === oct); // true
console.log(big);   // 1000000
console.log(sci);   // 6.022e+23
Numeric separators
The underscores in `1_000_000` or `0b1111_1111` are ignored by the engine — they are purely a readability tool. Use them generously in long constants.
The 0.1 + 0.2 problem

The most-quoted JavaScript gotcha is not a JavaScript bug — it is a property of binary floating-point shared by Python, Java, C and almost every other mainstream language.

JS
console.log(0.1 + 0.2);            // 0.30000000000000004
console.log(0.1 + 0.2 === 0.3);    // false

The numbers 0.1 and 0.2 cannot be stored exactly in binary; the tiny rounding errors accumulate when they're added. Two common ways to deal with it:

JS
// 1. Compare with a small tolerance (epsilon)
const a = 0.1 + 0.2;
console.log(Math.abs(a - 0.3) < Number.EPSILON); // true

// 2. Work in the smallest unit (e.g. cents, not dollars)
const totalCents = 10 + 20;       // 30
const totalDollars = totalCents / 100; // 0.3
Never use floats for money
Add prices in cents (or use a `BigInt` / decimal library). `0.1 + 0.2` quietly producing `0.30000000000000004` has caused real billing bugs.
Special values: NaN, Infinity, -0

A few numbers behave unlike "ordinary" numbers and trip up beginners constantly.

JS
// Infinity — from overflow or explicit division by zero
console.log(1 / 0);          // Infinity
console.log(-1 / 0);         // -Infinity
console.log(1e308 * 10);     // Infinity

// NaN — "not a number". The result of an impossible numeric operation.
console.log(0 / 0);          // NaN
console.log(Math.sqrt(-1));  // NaN
console.log(Number("abc"));  // NaN

// NaN is the only value not equal to itself
console.log(NaN === NaN);    // false
console.log(Number.isNaN(NaN)); // true — use this to test

// Signed zero — yes, JavaScript has -0
console.log(0 === -0);       // true
console.log(Object.is(0, -0)); // false — Object.is can tell them apart
console.log(1 / -0);         // -Infinity
Why -0?
The sign of zero is preserved because some numeric algorithms (notably in graphics and physics) care which direction you approached zero from. You can mostly ignore it.
Useful constants on the Number object

JS
Number.MAX_SAFE_INTEGER;   // 9007199254740991
Number.MIN_SAFE_INTEGER;   // -9007199254740991
Number.MAX_VALUE;          // ~1.79e308
Number.MIN_VALUE;          // ~5e-324  (smallest positive, not most negative)
Number.POSITIVE_INFINITY;  // Infinity
Number.NEGATIVE_INFINITY;  // -Infinity
Number.EPSILON;            // ~2.22e-16 — smallest meaningful difference near 1
Number.NaN;                // NaN

A number is "safe" if it can be represented exactly as a double and is not the result of rounding any other integer. Beyond MAX_SAFE_INTEGER, you can no longer trust integer arithmetic.

JS
console.log(Number.MAX_SAFE_INTEGER);       // 9007199254740991
console.log(Number.MAX_SAFE_INTEGER + 1);   // 9007199254740992
console.log(Number.MAX_SAFE_INTEGER + 2);   // 9007199254740992  (!)
9007199254740991
9007199254740992
9007199254740992

If you need exact integers beyond that range — large IDs from a database, cryptocurrency amounts, big factorials — use BigInt (covered on its own page).

Quick reference: precision gotchas
  • 0.1 + 0.2 !== 0.3 — use a tolerance or work in integers.

  • Math.max() === -Infinity and Math.min() === Infinity — the "identity" elements when no arguments are passed.

  • parseInt("0.1") is 0, not 0.1parseInt stops at the dot.

  • + "12px" is NaN — coercion is strict, parseInt("12px") gives 12.

  • 1 / 0 is Infinity, not an error. Check with Number.isFinite before dividing.

Numbers feel simple — and for everyday counts and prices they are — but the IEEE 754 model leaks through in small, predictable ways. The rest of this section covers the methods you'll use to round, parse, format and inspect numeric values safely.