¿Este for
bucle se detiene alguna vez?
for (var i=0; 1/i > 0; i++) {
}
Si es así, cuándo y por qué? Me dijeron que se detiene, pero no me dieron ninguna razón para ello.
Actualización
Como parte de la investigación, he escrito un artículo bastante extenso y detallado que explica todo lo que está sucediendo bajo el capó: esto es lo que necesita saber sobre el tipo de número de JavaScript
javascript
Max Koretskyi
fuente
fuente
Number.MAX_SAFE_INTEGER + 1
.Respuestas:
(No soy un fanático del metacontenido , pero: las respuestas de gotnull y le_m son correctas y útiles. Originalmente lo eran, y lo son aún más con las ediciones realizadas después de la publicación de esta Wiki de la comunidad. La motivación original de este CW desapareció en gran medida como resultado de esas ediciones, pero sigue siendo útil, así que ... Además: si bien solo hay un par de autores en la lista, muchos otros miembros de la comunidad han ayudado mucho con comentarios que se han incorporado y limpiado. no es solo un CW de nombre).
El ciclo no se detendrá en un motor JavaScript implementado correctamente. (El entorno de host del motor podría eventualmente terminarlo porque es interminable, pero eso es otra cosa).
Este es el por qué:
Inicialmente, cuando
i
es0
, la condición1/i > 0
es verdadera porque en JavaScript,1/0
esInfinity
yInfinity > 0
es verdadera.Después de eso,
i
se incrementará y seguirá creciendo como un valor entero positivo durante mucho tiempo (otras 9,007,199,254,740,991 iteraciones). En todos esos casos,1/i
permanecerá> 0
(¡aunque los valores de se1/i
vuelven realmente pequeños hacia el final!) Y así el ciclo continúa hasta e incluyendo el ciclo dondei
alcanza el valorNumber.MAX_SAFE_INTEGER
.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:
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 dondei
yi + 1
ambos 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):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!
Después de completar el
i = 9,007,199,254,740,992
ciclo,i++
nos da ... dei = 9,007,199,254,740,992
nuevo; no hay ningún cambioi
, porque el siguiente entero no se puede almacenar y el cálculo termina redondeando hacia abajo.i
cambiaría si lo hiciéramosi += 2
, peroi++
no podemos cambiarlo. Así que hemos alcanzado el estado estable:i
nunca cambia y el ciclo nunca termina.Aquí están los diversos cálculos relevantes:
fuente
Responder:
La condición
1/i > 0
siempre se evaluará como verdadera:Inicialmente es cierto porque
1/0
se evalúa comoInfinity
yInfinity > 0
es ciertoSigue siendo cierto ya que
1/i > 0
es cierto para todosi < Infinity
yi++
nunca llegaInfinity
.¿Por qué
i++
nunca llegaInfinity
? Debido a la precisión limitada delNumber
tipo de datos, existe un valor para el cuali + 1 == i
:Una vez
i
que alcance ese valor (que corresponde a ), seguirá siendo el mismo incluso después .Number.MAX_SAFE_INTEGER
+ 1
i++
Por tanto, tenemos un bucle infinito.
Apéndice:
¿Por qué es
9007199254740992 + 1 == 9007199254740992
?El
Number
tipo de datos de JavaScript es en realidad un flotante de doble precisión IEEE 754 de 64 bits . Cada unoNumber
se desmonta y almacena en tres partes: signo de 1 bit, exponente de 11 bits y mantisa de 52 bits. Su valor es -1 signo × mantisa × 2 exponente .¿Cómo se representa 9007199254740992 ? Como 1.0 × 2 53 , o en binario:
Incrementando el bit menos significativo de la mantisa, obtenemos el siguiente número más alto:
El valor de ese número es 1.00000000000000022… × 2 53 = 9007199254740994
Qué significa eso?
Number
puede ser 900719925474099 2 o 900719925474099 4 , pero nada intermedio.Ahora, ¿cuál elegiremos para representar 900719925474099 2 + 1 ? Las reglas de redondeo de IEEE 754 dan la respuesta: 900719925474099 2 .
fuente
for (var i = 0; i < Infinity; i += 1E306);
. Pero entiendo de dónde vienes;)La
Number.MAX_SAFE_INTEGER
constante representa el número entero seguro máximo en JavaScript. LaMAX_SAFE_INTEGER
constante tiene un valor de9007199254740991
. El razonamiento detrás de ese número es que JavaScript usa números de formato de punto flotante de doble precisión como se especifica en IEEE 754 y solo puede representar con seguridad números entre - (2 53 - 1) y 2 53 - 1.Seguro en este contexto se refiere a la capacidad de representar números enteros de forma exacta y compararlos correctamente. Por ejemplo,
Number.MAX_SAFE_INTEGER + 1 === Number.MAX_SAFE_INTEGER + 2
evaluará atrue
, que es matemáticamente incorrecto. ConsulteNumber.isSafeInteger()
para obtener más información.Debido a que
MAX_SAFE_INTEGER
es una propiedad estática deNumber
, siempre la usaNumber.MAX_SAFE_INTEGER
como una propiedad de unNumber
objeto que ha creado y no como una propiedad .ACTUALIZAR:
Alguien en una respuesta que se eliminó mencionó:
i
nunca llegará al infinito. Una vez que llegaNumber.MAX_SAFE_INTEGER
,i++
ya no incrementa la variable. De hecho, esto no es correcto.@TJ Crowder comenta que
i = Number.MAX_SAFE_INTEGER; i++; i == Number.MAX_SAFE_INTEGER;
esfalse
. Pero la siguiente iteración alcanza un estado invariable, por lo que la respuesta en main es correcta.i
en el ejemplo nunca llegaInfinity
.fuente
9007199254740992 + 1
es9007199254740992
.for (var i=0; NaN > 0; i++) { console.log(i); }
no producirá nada.1/i > 0
) sería falsa, ya que sii
es0
,1/i
esNaN
yNaN > 0
es falso.