Skip to content

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 ** 53 hold, 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_INTEGER and Number.isSafeInteger mean by safe, and why is 2 ** 53 itself not safe?
  • What does JSON.parse do to a 20-digit id, and how does the reviver's context.source read it exactly as a BigInt?
  • What happens to a counter that keeps adding 1 once it reaches 2^53?
  • What do Number(9007199254740993n) and BigInt(2 ** 53 + 1) return?

Examples it will need

  • safe_integers_edge_js.js — the integers from 2^53 - 2 to 2^53 + 4 as Number and as BigInt, with Number.isSafeInteger for each
  • safe_integers_json_id_js.js — a 20-digit id through plain JSON.parse, then read exactly with the reviver's context.source and BigInt, then written back with JSON.rawJSON

See also

Sources to start from