Integer Precision Limits in Float64

Learn why JavaScript's Number.MAX_SAFE_INTEGER is 2^53-1 and what happens when you exceed it. Understand the relationship between mantissa bits and integer precision.

Precision

Decimal Value

9007199254740992

Float32 Hex

0x5A000000

Float64 Hex

0x4340000000000000

Detailed Explanation

JavaScript and other languages that use float64 as their primary number type can represent integers exactly only up to a certain limit. Beyond that limit, consecutive integers cannot be distinguished.

The safe integer range:

Number.MAX_SAFE_INTEGER = 2^53 - 1 = 9007199254740991
Number.MIN_SAFE_INTEGER = -(2^53 - 1) = -9007199254740991

Why 2^53?

Float64 has 52 mantissa bits plus one implicit leading bit, giving 53 bits of significand precision. An integer that fits in 53 bits can be stored exactly. Integers requiring 54 or more bits must be rounded.

What happens at the boundary:

9007199254740991 + 1  // 9007199254740992 ✓ (exact, it's 2^53)
9007199254740992 + 1  // 9007199254740992 ✗ (should be ...993, but rounds to ...992)
9007199254740992 + 2  // 9007199254740994 ✓ (even numbers at this magnitude are exact)
9007199254740993 === 9007199254740992  // true! (they cannot be distinguished)

At 2^53, the ULP (gap between representable values) becomes 2. So only even integers are representable. At 2^54, the gap becomes 4, and only multiples of 4 are exact.

Practical consequences:

  1. Database IDs: IDs from databases (like Twitter's snowflake IDs) that exceed 2^53 lose precision when parsed as JavaScript numbers. This is why APIs often return large IDs as strings.

  2. Financial calculations: 0.01 (1 cent) cannot be represented exactly in float64. Working with cents as integers avoids this, but only if the integer does not exceed MAX_SAFE_INTEGER.

  3. Bitwise operations: JavaScript's bitwise operators (|, &, ^, ~, <<, >>) work on 32-bit integers, truncating any higher bits. (2**53) | 0 gives 0.

Solutions:

  • BigInt (JavaScript): 9007199254740993n + 1n works correctly
  • Long (Java): 64-bit integer with range up to 2^63 - 1
  • Decimal libraries: for exact decimal arithmetic
  • String representation: pass large IDs as strings in JSON

Testing for safe integers:

Number.isSafeInteger(9007199254740991)  // true
Number.isSafeInteger(9007199254740992)  // false (2^53 is not safe)
Number.isSafeInteger(1.5)               // false (not an integer)

Use Case

Understanding integer precision limits is crucial for web developers working with APIs that return large numeric IDs, financial applications performing arithmetic on currency values, and anyone porting code between languages with different integer and floating-point representations.

Try It — IEEE 754 Inspector

Open full tool