Los números en JavaScript son de coma flotante binaria de doble precisión IEEE-754, un formato bastante compacto (64 bits) que proporciona cálculos rápidos y una amplia gama. Lo hace almacenando el número como un bit de signo, un exponente de 11 bits y un significando de 52 bits (aunque gracias a la astucia, en realidad obtiene 53 bits de precisión). Es un punto flotante binario (base 2): el significado (más un poco de inteligencia) nos da el valor, y el exponente nos da la magnitud del número.
Naturalmente, con tantos bits significativos, no se pueden almacenar todos los números. Aquí es el número 1, y el siguiente número más alto después del 1 de que el formato puede almacenar, 1 + 2 -52 ≈ 1.00000000000000022, y el siguiente más alto después de que 1 + 2 × 2 -52 ≈ 1.00000000000000044:
+ ------------------------------------------------- -------------- firmar bit
/ + ------- + ---------------------------------------- -------------- exponente
/ / | + ------------------------------------------------- + - significando
/ / | / |
0 01111111111 0000000000000000000000000000000000000000000000000000
= 1
0 01111111111 0000000000000000000000000000000000000000000000000001
≈ 1.00000000000000022
0 01111111111 0000000000000000000000000000000000000000000000000010
≈ 1.00000000000000044
Note el salto de 1.00000000000000022 a 1.00000000000000044; no hay forma de almacenar 1.0000000000000003. Eso también puede suceder con los números enteros: Number.MAX_SAFE_INTEGER(9,007,199,254,740,991) es el valor entero positivo más alto que el formato puede contener donde iy i + 1ambos son exactamente representables ( especificación ). Se pueden representar tanto 9,007,199,254,740,991 como 9,007,199,254,740,992, pero el siguiente entero, 9,007,199,254,740,993, no puede; el siguiente entero que podemos representar después de 9,007,199,254,740,992 es 9,007,199,254,740,994. Aquí están los patrones de bits, tenga en cuenta el bit más a la derecha (menos significativo):
+ ------------------------------------------------- -------------- firmar bit
/ + ------- + ---------------------------------------- -------------- exponente
/ / | + ------------------------------------------------- + - significando
/ / | / |
0 10000110011 11111111111111111111111111111111111111111111111111
= 9007199254740991 (Número.MAX_SAFE_INTEGER)
0 10000110100 0000000000000000000000000000000000000000000000000000
= 9007199254740992 (Número.MAX_SAFE_INTEGER + 1)
x xxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
9007199254740993 (Número.MAX_SAFE_INTEGER + 2) no se puede almacenar
0 10000110100 0000000000000000000000000000000000000000000000000001
= 9007199254740994 (Número.MAX_SAFE_INTEGER + 3)
Recuerde, el formato es base 2, y con ese exponente el bit menos significativo ya no es fraccionario; tiene un valor de 2. Puede estar desactivado (9,007,199,254,740,992) o activado (9,007,199,254,740,994); así que en este punto, hemos comenzado a perder precisión incluso en la escala de números enteros (enteros). ¡Lo que tiene implicaciones para nuestro bucle!