Safe integers — past 2^53, adding 1 can change nothing¶
Level: 201 · for anyone who stores ids, counters or timestamps as numbers
Stub — an outline, not a lesson. There is no runnable example behind this page yet, so nothing on it has been through the check that backs every other claim in this library. The questions below are what the finished page has to answer.
One line: Above 2^53 a double skips integers (between 2^53 and 2^54 it holds only even ones), so 2 ** 53 + 1 === 2 ** 53 is true, the literal 9007199254740993 prints 9007199254740992, and JSON.parse rounds a 20-digit id without a word; BigInt keeps every digit.
Keywords: Number.MAX_SAFE_INTEGER, Number.MIN_SAFE_INTEGER, Number.isSafeInteger, safe integer
What the finished page will answer¶
- Why does
2 ** 53 + 1 === 2 ** 53hold, and which integers can a double represent between 2^53 and 2^54, and between 2^54 and 2^55? - What do
Number.MAX_SAFE_INTEGERandNumber.isSafeIntegermean by safe, and why is2 ** 53itself not safe? - What does
JSON.parsedo to a 20-digit id, and how does the reviver'scontext.sourceread it exactly as aBigInt? - What happens to a counter that keeps adding 1 once it reaches 2^53?
- What do
Number(9007199254740993n)andBigInt(2 ** 53 + 1)return?
Examples it will need¶
-
safe_integers_edge_js.js— the integers from 2^53 - 2 to 2^53 + 4 asNumberand asBigInt, withNumber.isSafeIntegerfor each -
safe_integers_json_id_js.js— a 20-digit id through plainJSON.parse, then read exactly with the reviver'scontext.sourceandBigInt, then written back withJSON.rawJSON
See also¶
- Every number is a double — the 53-bit significand behind the limit
- BigInt — integers with no fixed width, for values past 2^53
- JSON — what
JSON.parseandJSON.stringifydo to numbers - External data — the rounded id still has the type
numberin TypeScript - Rust: Big integers:
BigIntand Python'sint↗ — theu128ceiling in Rust, and the Pythonintthat has none - Python: Comparing an
intwith afloat↗ — in Python, a bigintand afloatcompare exactly