Why is Number.MAX_SAFE_INTEGER 9,007,199,254,740,991 and not 9,007,199,254,740,992?

JavascriptEcmascript 6IntegerIeee 754

Javascript Problem Overview


ECMAScript 6's Number.MAX_SAFE_INTEGER supposedly represents the maximum numerical value JavaScript can store before issues arise with floating point precision. However it's a requirement that the number 1 added to this value must also be representable as a Number.

> ### Number.MAX_SAFE_INTEGER > > NOTE The value of Number.MAX_SAFE_INTEGER is the largest integer n such that n and n + 1 are both exactly representable as a Number value. > > The value of Number.MAX_SAFE_INTEGER is 9007199254740991 (2^53−1). > > – ECMAScript Language Specification

The JavaScript consoles of Chrome, Firefox, Opera and IE11 can all safely perform calculations with the number 9,007,199,254,740,992. Some tests:

// Valid
Math.pow(2, 53)                         // 9007199254740992
9007199254740991 + 1                    // 9007199254740992
9007199254740992 - 1                    // 9007199254740991
9007199254740992 / 2                    // 4503599627370496
4503599627370496 * 2                    // 9007199254740992
parseInt('20000000000000', 16)          // 9007199254740992
parseInt('80000000000', 32)             // 9007199254740992
9007199254740992 - 9007199254740992     // 0
9007199254740992 == 9007199254740991    // false
9007199254740992 == 9007199254740992    // true

// Erroneous
9007199254740992 + 1                    // 9007199254740992
9007199254740993 + ""                   // "9007199254740992"
9007199254740992 == 9007199254740993    // true

Why is it a requirement that n + 1 must also be representable as a Number? Why does failing this make the value unsafe?

Javascript Solutions


Solution 1 - Javascript

I would say its because while Math.pow(2, 53) is the largest directly representable integer, its unsafe in that its also the first value who's representation is also an approximation of another value:

9007199254740992 == 9007199254740993 // true

In contrast to Math.pow(2, 53) - 1:

9007199254740991 == 9007199254740993 // false

Solution 2 - Javascript

the only number which is in close proximity of another when compared with its next number shows true

9007199254740992 == 9007199254740993
true
9007199254740993 == 9007199254740994
false
9007199254740991 == 9007199254740992
false
9007199254740997 == 9007199254740998
false

Solution 3 - Javascript

I also have the same concern about the question. said the safe range is -2^53~2^53(Including boundary values) while said the range is-2^53+1~2^53-1.

Finally, I found the Correct interpretation in https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isSafeInteger

It said, the "safe"means :

  1. can be exactly represented as an IEEE-754 double precision number, and
  2. whose IEEE-754 representation cannot be the result of rounding any other integer to fit the IEEE-754 representation.

So 2^53 is not a safe integer because : it can be exactly represented in IEEE-754, but the integer 2^53 + 1 can't be directly represented in IEEE-754 but instead rounds to 2^53 under round-to-nearest and round-to-zero rounding.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJames DonnellyView Question on Stackoverflow
Solution 1 - JavascriptAlex K.View Answer on Stackoverflow
Solution 2 - JavascriptMerita Wilson HView Answer on Stackoverflow
Solution 3 - JavascriptEmonView Answer on Stackoverflow