Number.MAX_SAFE_INTEGER incorrect?

classic Classic list List threaded Threaded
10 messages Options
Reply | Threaded
Open this post in threaded view
|

Number.MAX_SAFE_INTEGER incorrect?

Anders Rundgren-2
If you write
Number.MAX_SAFE_INTEGER
into a browser console it will return
9007199254740991

I believe this is wrong, 9007199254740992 the largest correct safe integer using IEEE-754 double precision.

Using my own IEEE-754 debugger:

Input floating point: 9007199254740991
Hex value: 433fffffffffffff
Binary value: 0 10000110011 1111111111111111111111111111111111111111111111111111

Input floating point: 9007199254740992
Hex value: 4340000000000000
Binary value: 0 10000110100 0000000000000000000000000000000000000000000000000000

Using an external IEEE-754 debugger:
http://www.binaryconvert.com/result_double.html?decimal=057048048055049057057050053052055052048057057050

Anders
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Number.MAX_SAFE_INTEGER incorrect?

Isiah Meadows-2
Technically, "safe" in this context means "can you store this number *and all numbers below it* without loss of precision", and for every single one of these numbers, you can still add one to them. When you get up to 2^53, you can no longer add just 1 - you can only add 2 or more. This is based on the number of significand bits - 2^53 - 1 has all lower 53 bits set and its exponent set to 0 (ignoring bias). You can precisely store up to this number without having to adjust the exponent, no more. This is what is meant by "safe". (The terminology of "exactly representable" is a misnomer - the highest integer you can theoretically represent without loss of precision is `(2^53-1) * (2^971)`.)

This SO answer should help explain the situation better: https://stackoverflow.com/a/1848762



On Sun, May 6, 2018 at 11:58 AM, Anders Rundgren <[hidden email]> wrote:
If you write
Number.MAX_SAFE_INTEGER
into a browser console it will return
9007199254740991

I believe this is wrong, 9007199254740992 the largest correct safe integer using IEEE-754 double precision.

Using my own IEEE-754 debugger:

Input floating point: 9007199254740991
Hex value: 433fffffffffffff
Binary value: 0 10000110011 1111111111111111111111111111111111111111111111111111

Input floating point: 9007199254740992
Hex value: 4340000000000000
Binary value: 0 10000110100 0000000000000000000000000000000000000000000000000000

Using an external IEEE-754 debugger:
http://www.binaryconvert.com/result_double.html?decimal=057048048055049057057050053052055052048057057050

Anders
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Number.MAX_SAFE_INTEGER incorrect?

Anders Rundgren-2
On 2018-05-06 18:40, Isiah Meadows wrote:
> Technically, "safe" in this context means "can you store this number *and all numbers below it* without loss of precision", and for every single one of these numbers, you can still add one to them. When you get up to 2^53, you can no longer add just 1 - you can only add 2 or more. This is based on the number of significand bits - 2^53 - 1 has all lower 53 bits set and its exponent set to 0 (ignoring bias). You can precisely store up to this number without having to adjust the exponent, no more. This is what is meant by "safe". (The terminology of "exactly representable" is a misnomer - the highest integer you can theoretically represent without loss of precision is `(2^53-1) * (2^971)`.)

Thanx Isiah,
I (sort of) understand :-)

Anyway, this definition departs from similar definitions in other languages and AFAICT, existing JavaScript implementations have no problems using 2^53 as an integer.

 > var t = 9007199254740992
< undefined
 > t-1
< 9007199254740991
 > t
< 9007199254740992

For JavaScript this may be of limited importance but for (I-)JSON canonicalization [1] it is vital that all parties do the same interpretation.
That is, for I-JSON the 2^53-1 limitation is simply put wrong.

Anders

1] https://github.com/cyberphone/json-canonicalization#json-canonicalization


>
> This SO answer should help explain the situation better: https://stackoverflow.com/a/1848762
>
>
> -----
>
> Isiah Meadows
> [hidden email] <mailto:[hidden email]>
> www.isiahmeadows.com <http://www.isiahmeadows.com>
>
> On Sun, May 6, 2018 at 11:58 AM, Anders Rundgren <[hidden email] <mailto:[hidden email]>> wrote:
>
>     If you write
>     Number.MAX_SAFE_INTEGER
>     into a browser console it will return
>     9007199254740991
>
>     I believe this is wrong, 9007199254740992 the largest correct safe integer using IEEE-754 double precision.
>
>     Using my own IEEE-754 debugger:
>
>     Input floating point: 9007199254740991
>     Hex value: 433fffffffffffff
>     Binary value: 0 10000110011 1111111111111111111111111111111111111111111111111111
>
>     Input floating point: 9007199254740992
>     Hex value: 4340000000000000
>     Binary value: 0 10000110100 0000000000000000000000000000000000000000000000000000
>
>     Using an external IEEE-754 debugger:
>     http://www.binaryconvert.com/result_double.html?decimal=057048048055049057057050053052055052048057057050 <http://www.binaryconvert.com/result_double.html?decimal=057048048055049057057050053052055052048057057050>
>
>     Anders
>     _______________________________________________
>     es-discuss mailing list
>     [hidden email] <mailto:[hidden email]>
>     https://mail.mozilla.org/listinfo/es-discuss <https://mail.mozilla.org/listinfo/es-discuss>
>
>

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Number.MAX_SAFE_INTEGER incorrect?

Logan Smyth
To clarify, the "you can still add one to them" is probably the most important part in that definition, given your question.

Anyway, this definition departs from similar definitions in other languages and AFAICT, existing JavaScript implementations have no problems using 2^53 as an integer.

2^53 can be represented just fine, but `2**53 + 1 === 2**53` is `true`, so adding one to it does not actually increment the value, meaning it does not satisfy the definition of `SAFE` in this context.

I think the best source of truth is likely the spec: https://www.ecma-international.org/ecma-262/8.0/#sec-number.max_safe_integer which states

> 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.


On Sun, May 6, 2018 at 10:47 AM, Anders Rundgren <[hidden email]> wrote:
On 2018-05-06 18:40, Isiah Meadows wrote:
Technically, "safe" in this context means "can you store this number *and all numbers below it* without loss of precision", and for every single one of these numbers, you can still add one to them. When you get up to 2^53, you can no longer add just 1 - you can only add 2 or more. This is based on the number of significand bits - 2^53 - 1 has all lower 53 bits set and its exponent set to 0 (ignoring bias). You can precisely store up to this number without having to adjust the exponent, no more. This is what is meant by "safe". (The terminology of "exactly representable" is a misnomer - the highest integer you can theoretically represent without loss of precision is `(2^53-1) * (2^971)`.)

Thanx Isiah,
I (sort of) understand :-)

Anyway, this definition departs from similar definitions in other languages and AFAICT, existing JavaScript implementations have no problems using 2^53 as an integer.

> var t = 9007199254740992
< undefined
> t-1
< 9007199254740991
> t
< 9007199254740992

For JavaScript this may be of limited importance but for (I-)JSON canonicalization [1] it is vital that all parties do the same interpretation.
That is, for I-JSON the 2^53-1 limitation is simply put wrong.

Anders

1] https://github.com/cyberphone/json-canonicalization#json-canonicalization



This SO answer should help explain the situation better: https://stackoverflow.com/a/1848762


-----

Isiah Meadows
[hidden email] <mailto:[hidden email]>
www.isiahmeadows.com <http://www.isiahmeadows.com>

On Sun, May 6, 2018 at 11:58 AM, Anders Rundgren <[hidden email] <mailto:[hidden email]>> wrote:

    If you write
    Number.MAX_SAFE_INTEGER
    into a browser console it will return
    9007199254740991

    I believe this is wrong, 9007199254740992 the largest correct safe integer using IEEE-754 double precision.

    Using my own IEEE-754 debugger:

    Input floating point: 9007199254740991
    Hex value: 433fffffffffffff
    Binary value: 0 10000110011 1111111111111111111111111111111111111111111111111111

    Input floating point: 9007199254740992
    Hex value: 4340000000000000
    Binary value: 0 10000110100 0000000000000000000000000000000000000000000000000000

    Using an external IEEE-754 debugger:
    http://www.binaryconvert.com/result_double.html?decimal=057048048055049057057050053052055052048057057050 <http://www.binaryconvert.com/result_double.html?decimal=057048048055049057057050053052055052048057057050>

    Anders
    _______________________________________________
    es-discuss mailing list
    [hidden email] <mailto:[hidden email]>
    https://mail.mozilla.org/listinfo/es-discuss <https://mail.mozilla.org/listinfo/es-discuss>



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Number.MAX_SAFE_INTEGER incorrect?

Mark Miller-2
motivation:

if (isSafeInteger(a) && isSafeInteger(b)) {
  const c = a + b;
  if (isSafeInteger(b)) {
    // c is actually the sum of a and b
  }
}



On Sun, May 6, 2018 at 10:57 AM, Logan Smyth <[hidden email]> wrote:
To clarify, the "you can still add one to them" is probably the most important part in that definition, given your question.

Anyway, this definition departs from similar definitions in other languages and AFAICT, existing JavaScript implementations have no problems using 2^53 as an integer.

2^53 can be represented just fine, but `2**53 + 1 === 2**53` is `true`, so adding one to it does not actually increment the value, meaning it does not satisfy the definition of `SAFE` in this context.

I think the best source of truth is likely the spec: https://www.ecma-international.org/ecma-262/8.0/#sec-number.max_safe_integer which states

> 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.


On Sun, May 6, 2018 at 10:47 AM, Anders Rundgren <[hidden email]> wrote:
On 2018-05-06 18:40, Isiah Meadows wrote:
Technically, "safe" in this context means "can you store this number *and all numbers below it* without loss of precision", and for every single one of these numbers, you can still add one to them. When you get up to 2^53, you can no longer add just 1 - you can only add 2 or more. This is based on the number of significand bits - 2^53 - 1 has all lower 53 bits set and its exponent set to 0 (ignoring bias). You can precisely store up to this number without having to adjust the exponent, no more. This is what is meant by "safe". (The terminology of "exactly representable" is a misnomer - the highest integer you can theoretically represent without loss of precision is `(2^53-1) * (2^971)`.)

Thanx Isiah,
I (sort of) understand :-)

Anyway, this definition departs from similar definitions in other languages and AFAICT, existing JavaScript implementations have no problems using 2^53 as an integer.

> var t = 9007199254740992
< undefined
> t-1
< 9007199254740991
> t
< 9007199254740992

For JavaScript this may be of limited importance but for (I-)JSON canonicalization [1] it is vital that all parties do the same interpretation.
That is, for I-JSON the 2^53-1 limitation is simply put wrong.

Anders

1] https://github.com/cyberphone/json-canonicalization#json-canonicalization



This SO answer should help explain the situation better: https://stackoverflow.com/a/1848762


-----

Isiah Meadows
[hidden email] <mailto:[hidden email]>
www.isiahmeadows.com <http://www.isiahmeadows.com>

On Sun, May 6, 2018 at 11:58 AM, Anders Rundgren <[hidden email] <mailto:[hidden email]>> wrote:

    If you write
    Number.MAX_SAFE_INTEGER
    into a browser console it will return
    9007199254740991

    I believe this is wrong, 9007199254740992 the largest correct safe integer using IEEE-754 double precision.

    Using my own IEEE-754 debugger:

    Input floating point: 9007199254740991
    Hex value: 433fffffffffffff
    Binary value: 0 10000110011 1111111111111111111111111111111111111111111111111111

    Input floating point: 9007199254740992
    Hex value: 4340000000000000
    Binary value: 0 10000110100 0000000000000000000000000000000000000000000000000000

    Using an external IEEE-754 debugger:
    http://www.binaryconvert.com/result_double.html?decimal=057048048055049057057050053052055052048057057050 <http://www.binaryconvert.com/result_double.html?decimal=057048048055049057057050053052055052048057057050>

    Anders
    _______________________________________________
    es-discuss mailing list
    [hidden email] <mailto:[hidden email]>
    https://mail.mozilla.org/listinfo/es-discuss <https://mail.mozilla.org/listinfo/es-discuss>



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss




--
  Cheers,
  --MarkM

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Number.MAX_SAFE_INTEGER incorrect?

Mark Miller-2
Oops. Should be:

if (isSafeInteger(a) && isSafeInteger(b)) {
  const c = a + b;
  if (isSafeInteger(c)) {
    // c is actually the sum of a and b
  }
}


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Number.MAX_SAFE_INTEGER incorrect?

Anders Rundgren-2
In reply to this post by Logan Smyth
On 2018-05-06 19:57, Logan Smyth wrote:
<snip>
> I think the best source of truth is likely the spec: https://www.ecma-international.org/ecma-262/8.0/#sec-number.max_safe_integer which states
>
> 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.

Right, this is essentially what I'm claiming; Number.MAX_SAFE_INTEGER + 1 is a valid (exact) integer which means that https://tools.ietf.org/html/rfc7493#section-2.2 is incorrect.

Anders
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Number.MAX_SAFE_INTEGER incorrect?

Mark Miller-2
Hi Anders, you are correct. The rfc as stated is incorrect. The EcmaScript spec is correct. 

2**53 is indeed exactly representable, which is what the rfc is about. But 2**53 is not safe, which what the ecmascript spec is about.



On Sun, May 6, 2018 at 11:58 AM, Anders Rundgren <[hidden email]> wrote:
On 2018-05-06 19:57, Logan Smyth wrote:
<snip>
I think the best source of truth is likely the spec: https://www.ecma-international.org/ecma-262/8.0/#sec-number.max_safe_integer which states

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.

Right, this is essentially what I'm claiming; Number.MAX_SAFE_INTEGER + 1 is a valid (exact) integer which means that https://tools.ietf.org/html/rfc7493#section-2.2 is incorrect.

Anders
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss



--
  Cheers,
  --MarkM

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Number.MAX_SAFE_INTEGER incorrect?

Mark Miller-2
I take that back. The rfc says:

   An I-JSON sender cannot expect a receiver to treat an integer whose
   absolute value is greater than 9007199254740991 (i.e., that is
   outside the range [-(2**53)+1, (2**53)-1]) as an exact value.

For the natural interpretation of "treat" as in "operate on or with" I'd say the rfc is correct. But the language is ambiguous and should be clarified.




On Sun, May 6, 2018 at 12:34 PM, Mark Miller <[hidden email]> wrote:
Hi Anders, you are correct. The rfc as stated is incorrect. The EcmaScript spec is correct. 

2**53 is indeed exactly representable, which is what the rfc is about. But 2**53 is not safe, which what the ecmascript spec is about.



On Sun, May 6, 2018 at 11:58 AM, Anders Rundgren <[hidden email]> wrote:
On 2018-05-06 19:57, Logan Smyth wrote:
<snip>
I think the best source of truth is likely the spec: https://www.ecma-international.org/ecma-262/8.0/#sec-number.max_safe_integer which states

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.

Right, this is essentially what I'm claiming; Number.MAX_SAFE_INTEGER + 1 is a valid (exact) integer which means that https://tools.ietf.org/html/rfc7493#section-2.2 is incorrect.

Anders
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss



--
  Cheers,
  --MarkM



--
  Cheers,
  --MarkM

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Number.MAX_SAFE_INTEGER incorrect?

Anders Rundgren-2
On 2018-05-06 21:37, Mark Miller wrote:
> I take that back. The rfc says:
>
>     An I-JSON sender cannot expect a receiver to treat an integer whose
>     absolute value is greater than 9007199254740991 (i.e., that is
>     outside the range [-(2**53)+1, (2**53)-1]) as an exact value.
>
> For the natural interpretation of "treat" as in "operate on or with" I'd say the rfc is correct. But the language is ambiguous and should be clarified.

Well, the author questioned that IEEE-754 implementations actually deal with this edge case at all.

However, they do which I found out by testing with 9007199254740992 in order to break my canonicalizer implementations which to my surprise all continued to work.

Then, when looking at the binary, it became clear that Number.MAX_SAFE_INTEGER is not comparable to other languages' MAX* definitions.
https://docs.oracle.com/javase/8/docs/api/constant-values.html#java.lang.Integer.MAX_VALUE

Anyway, thanx for the insights in this matter!

Anders


>
>
>
>
> On Sun, May 6, 2018 at 12:34 PM, Mark Miller <[hidden email] <mailto:[hidden email]>> wrote:
>
>     Hi Anders, you are correct. The rfc as stated is incorrect. The EcmaScript spec is correct.
>
>     2**53 is indeed exactly representable, which is what the rfc is about. But 2**53 is not safe, which what the ecmascript spec is about.
>
>
>
>     On Sun, May 6, 2018 at 11:58 AM, Anders Rundgren <[hidden email] <mailto:[hidden email]>> wrote:
>
>         On 2018-05-06 19:57, Logan Smyth wrote:
>         <snip>
>
>             I think the best source of truth is likely the spec: https://www.ecma-international.org/ecma-262/8.0/#sec-number.max_safe_integer <https://www.ecma-international.org/ecma-262/8.0/#sec-number.max_safe_integer> which states
>
>             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.
>
>
>         Right, this is essentially what I'm claiming; Number.MAX_SAFE_INTEGER + 1 is a valid (exact) integer which means that https://tools.ietf.org/html/rfc7493#section-2.2 <https://tools.ietf.org/html/rfc7493#section-2.2> is incorrect.
>
>         Anders
>         _______________________________________________
>         es-discuss mailing list
>         [hidden email] <mailto:[hidden email]>
>         https://mail.mozilla.org/listinfo/es-discuss <https://mail.mozilla.org/listinfo/es-discuss>
>
>
>
>
>     --
>        Cheers,
>        --MarkM
>
>
>
>
> --
>    Cheers,
>    --MarkM

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss