# Floating-point number

Canonical URL: https://offlineutils.com/glossary/floating-point
Also known as: IEEE 754, double precision, binary64, float64, Number.MAX_SAFE_INTEGER, safe integer
Published: 2026-10-23
Publisher: offlineutils.com

> A floating-point number stores a value as a binary fraction scaled by a power of two. JavaScript's Number is an IEEE 754 double with 53 significant bits, so integers above 2^53 − 1 (9,007,199,254,740,991) and most decimal fractions, 0.1 included, cannot be stored exactly.

An IEEE 754 double spends its 64 bits on one sign bit, 11 exponent bits and 52 fraction bits, with an implicit leading 1 that makes 53 significant bits in all. Its precision is relative rather than absolute: about 15 to 17 significant decimal digits at any magnitude, with the gap between neighbouring values doubling at every power of two. Every integer up to 2^53 is exact. Between 2^53 and 2^54 only even numbers exist, and between 2^60 and 2^61 neighbouring values are 256 apart.

Decimal fractions are the other half of the story. 0.1 has no finite binary representation, just as 1/3 has no finite decimal one, so it is stored as the nearest double, and those small errors surface in arithmetic: 0.1 + 0.2 evaluates to 0.30000000000000004. That is correct IEEE 754 behaviour, not a JavaScript bug — Python, Java and C produce the same result. Money should be held as integer minor units such as cents, or in a decimal type, never as a float.

Large integers are where floating point corrupts data silently. JSON's grammar allows any number of digits, but JSON.parse turns every number into a double, so 9007199254740993 becomes 9007199254740992 without any error, and RFC 8259 warns that interoperability is only assured for integers within ±(2^53 − 1). 64-bit IDs and nanosecond timestamps routinely exceed that. A nanosecond Unix timestamp passed 2^53 on 15 April 1970; today's values are around 1.75 × 10^18, where neighbouring doubles are 256 nanoseconds apart, so 1753524000123456789 parses as 1753524000123456768. That is why OpenTelemetry's JSON encoding and Discord's API send 64-bit integers as strings.

JavaScript offers exact alternatives. BigInt holds integers of any size exactly, although JSON.stringify throws on it. JSON.parse can now hand a reviver the original source text of each number, and JSON.rawJSON writes digits back out unchanged — in Chrome 114, Firefox 135 and Safari 18.4 onwards. The simplest fix of all is to keep large identifiers as strings from end to end.

## Frequently asked questions

### Why does 0.1 + 0.2 not equal 0.3?

Because neither 0.1 nor 0.2 can be represented exactly in binary, so each is stored as the nearest double and the tiny errors add up: the sum is 0.30000000000000004. Every language using IEEE 754 doubles gives the same answer. Compare floating-point results with a tolerance suited to their magnitude, or do the arithmetic in integers — whole cents rather than fractional dollars.

### What is Number.MAX_SAFE_INTEGER?

It is 2^53 − 1, or 9,007,199,254,740,991: the largest integer below which every integer has its own exact double. Above it, doubles can no longer tell neighbouring integers apart, so Number.MAX_SAFE_INTEGER + 1 === Number.MAX_SAFE_INTEGER + 2 evaluates to true. Number.isSafeInteger() tells you whether a value is still in the exact range.

### Why does an ID or timestamp change when I parse JSON?

Because it is larger than 2^53 and JSON.parse converted it to a double, rounding it to the nearest value a double can hold — silently, with no error. 64-bit database IDs, Snowflake-style IDs and nanosecond timestamps are the usual victims. Send such values as strings, or parse them with a lossless parser; this site's JSON formatter re-emits the original digits exactly and flags numbers that JavaScript would round.

### Does JSON itself limit numbers to 2^53?

No. JSON's grammar allows a number of any length and precision; the limit belongs to the parser. RFC 8259 points out that many implementations use IEEE 754 doubles and recommends staying within ±(2^53 − 1) when interoperability matters, which is why APIs that handle 64-bit values usually transmit them as strings.

### How should money be stored?

As integers in the smallest unit — cents, pence, satoshis — or in a decimal type built for it, such as SQL DECIMAL. Floating point cannot represent most decimal fractions exactly, and rounding errors accumulate over sums and conversions until a ledger is off by a cent with no obvious cause.

## Related tools

- https://offlineutils.com/json-formatter
- https://offlineutils.com/timestamp-converter
- https://offlineutils.com/number-base-converter

## References

- https://en.wikipedia.org/wiki/Double-precision_floating-point_format
- https://datatracker.ietf.org/doc/html/rfc8259#section-6
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/MAX_SAFE_INTEGER
