usted está desbordando la capacidad del tipo de número de JavaScript, ver §8.5 of the spec para más detalles. Esas identificaciones necesitarán ser cadenas.
punto flotante de precisión doble IEEE-754 (el tipo de número que usa JavaScript) no puede representar con precisión todos los números (por supuesto). Famoso, 0.1 + 0.2 == 0.3
es falso. Eso puede afectar números enteros al igual que afecta a números fraccionarios; comienza una vez que obtiene por encima de 9,007,199,254,740,991 (Number.MAX_SAFE_INTEGER
).
Más allá de Number.MAX_SAFE_INTEGER + 1
(9007199254740992
), el formato de coma flotante IEEE-754 ya no puede representar todos los números enteros consecutivos. 9007199254740991 + 1
es 9007199254740992
, pero 9007199254740992 + 1
es también9007199254740992
porque 9007199254740993
no se pueden representar en el formato. El próximo que puede ser es 9007199254740994
. Entonces 9007199254740995
no puede ser, pero 9007199254740996
puede.
El motivo es que nos hemos quedado sin bits, por lo que ya no tenemos un bit 1; el bit de orden más bajo ahora representa múltiplos de 2. Eventualmente, si seguimos adelante, perdemos ese bit y solo trabajamos en múltiplos de 4. Y así sucesivamente.
Sus valores son y por encima de ese umbral, por lo que se redondean al valor representable más cercano.
Si eres curioso acerca de los bits, esto es lo que sucede: Un número binario de coma flotante de doble precisión IEEE-754 tiene un bit de signo, 11 bits de exponente (que define la escala global de la serie , como un poder de 2 [porque este es un formato binario]), y 52 bits de significado (pero el formato es tan inteligente que obtiene 53 bits de precisión de esos 52 bits). Cómo se usa el exponente es complicado (described here), pero en muy términos vagos, si agregamos uno al exponente, el valor del significado se duplica, ya que el exponente se usa para potencias de 2 (de nuevo, caveat there, no es directo, hay inteligencia allí).
Así que vamos a ver el valor 9007199254740991
(aka, Number.MAX_SAFE_INTEGER
):
+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− sign bit
/ +−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− exponent
// | +−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+− significand
// |/ |
0 10000110011 1111111111111111111111111111111111111111111111111111
= 9007199254740991 (Number.MAX_SAFE_INTEGER)
Ese valor del exponente, 10000110011
, quiere decir que cada vez que añadimos una a la mantisa, el número representado sube por 1 (el número 1, perdimos la capacidad de representar números fraccionarios mucho antes).
Pero ahora que significand está lleno. Para pasar ese número, tenemos que aumentar el exponente, lo que significa que si agregamos uno al significado, el valor del número representado aumenta en 2, no en 1 (porque el exponente se aplica a 2, la base de este número de punto flotante binario):
+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− sign bit
/ +−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− exponent
// | +−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+− significand
// |/ |
0 10000110100 0000000000000000000000000000000000000000000000000000
= 9007199254740992 (Number.MAX_SAFE_INTEGER + 1)
Bueno, eso está bien, porque es 9007199254740991 + 1
9007199254740992
de todos modos. ¡Pero! No podemos representar 9007199254740993
. Nos hemos quedado sin partes. Si añadimos a sólo 1 a la mantisa, que añade 2 al valor:
+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− sign bit
/ +−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− exponent
// | +−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+− significand
// |/ |
0 10000110100 0000000000000000000000000000000000000000000000000001
= 9007199254740994 (Number.MAX_SAFE_INTEGER + 3)
El formato no puede representar números impares más a medida que aumenta el valor, el exponente es demasiado grande.
Finalmente, nos quedamos sin bits significativos y tenemos que aumentar el exponente, por lo que solo podemos representar múltiplos de 4. Entonces múltiplos de 8. Luego múltiplos de 16. Y así sucesivamente.
Gracias a todos por sus rápidas respuestas útiles, me gustaría poder marcar las 3 respuestas oficiales. – Jaanus