Tenía un código simple que se suponía que era un bucle sin fin, ya x
que siempre estará creciendo y siempre será más grande que j
.
int x = 5;
int y = 9;
for (int j = 0; j < x; j++) {
x = x + y;
}
System.out.println(y);
pero como está, se imprime y
y no se repite sin fin. No puedo entender por qué. Sin embargo, cuando ajusto el código de la siguiente manera:
int x = 5;
int y = 9;
for (int j = 0; j < x; j++) {
x = x + y;
System.out.println(y);
}
System.out.println(y);
Se convierte en un bucle sin fin y no tengo ni idea de por qué. ¿Java reconoce que es un bucle sin fin y lo omite en la primera situación, pero tiene que ejecutar una llamada a un método en la segunda para que se comporte como se esperaba? Confundido :)
java
for-loop
infinite-loop
Omar
fuente
fuente
x
crece más rápido que la variable del cicloj
. En otras palabras,j
nunca alcanzará un límite superior, por lo tanto, el ciclo se ejecutará "para siempre". Bueno, no para siempre, lo más probable es que se desborde en algún momento.y
238609294 vecesSystem.out.println(x)
lugar dey
al final, habría mostrado instantáneamente cuál era el problemaRespuestas:
Ambos ejemplos no son infinitos.
El problema es la limitación del
int
tipo en Java (o prácticamente cualquier otro lenguaje común). Cuando el valor dex
alcanza0x7fffffff
, agregar cualquier valor positivo resultará en un desbordamiento y se volveráx
negativo, por lo tanto menor quej
.La diferencia entre el primer ciclo y el segundo es que el código interno lleva mucho más tiempo y probablemente se necesitarían varios minutos hasta que se
x
desborde. Para el primer ejemplo, puede llevar menos de un segundo o lo más probable es que el optimizador elimine el código, ya que no tiene ningún efecto.Como se mencionó en la discusión, el tiempo dependerá en gran medida de cómo el sistema operativo almacena en búfer la salida, si envía al emulador de terminal, etc., por lo que puede ser mucho más largo que unos pocos minutos.
fuente
println()
en Windows es una operación de bloqueo, mientras que en (¿algunos?) Unix está almacenado en búfer, por lo que va mucho más rápido. También intente usarprint()
, que búferes hasta que llegue a\n
(o el búfer se llene, oflush()
se llame)Dado que se declaran como int, una vez que alcanza el valor máximo, el bucle se romperá cuando el valor de x se vuelva negativo.
Pero cuando se agrega System.out.println al bucle, la velocidad de ejecución se vuelve visible (ya que la salida a la consola ralentizará la velocidad de ejecución). Sin embargo, si deja que el segundo programa (el que tiene syso dentro del ciclo) se ejecute durante el tiempo suficiente, debería tener el mismo comportamiento que el primero (el que no tiene syso dentro del ciclo).
fuente
Puede haber dos razones para esto:
Java optimiza el
for
ciclo y, dado que no se usax
después del ciclo, simplemente elimina el ciclo. Puede verificar esto poniendo unaSystem.out.println(x);
declaración después del ciclo.Es posible que Java en realidad no esté optimizando el bucle y esté ejecutando el programa correctamente y, finalmente
x
, crezca demasiadoint
y se desborde. El desbordamiento de enteros probablemente hará que el enterox
sea negativo, que será más pequeño que j, por lo que saldrá del ciclo e imprimirá el valor dey
. Esto también se puede verificar agregandoSystem.out.println(x);
después del ciclo.Además, incluso en el primer caso, eventualmente se producirá un desbordamiento, lo que lo convertirá en el segundo caso, por lo que nunca será un verdadero bucle sin fin.
fuente
sysout
es tan lento para agregar la ilusión de un bucle infinito.Ambos no son bucles infinitos, inicialmente j = 0, siempre que j <x, j aumente (j ++), y j es un número entero, por lo que el bucle se ejecutará hasta que alcance el valor máximo y luego se desborde (un desbordamiento de enteros es la condición que ocurre cuando el resultado de una operación aritmética, como una multiplicación o suma, excede el tamaño máximo del tipo de entero utilizado para almacenarlo). para el segundo ejemplo, el sistema simplemente imprime el valor de y hasta que se rompe el ciclo.
si está buscando un ejemplo de un bucle sin fin, debería verse así
porque (x) nunca alcanzaría el valor de 10;
también puede crear un bucle infinito con un bucle for doble:
este bucle es infinito porque el primer bucle for dice i <10, lo cual es cierto, así que entra en el segundo bucle for y el segundo bucle for aumenta el valor de (i) hasta que es == 5. Luego pasa al primero for bucle de nuevo porque i <10, el proceso sigue repitiéndose porque se reinicia después del segundo bucle for
fuente
Es un ciclo finito porque una vez que el valor de
x
excede2,147,483,647
(que es el valor máximo de anint
),x
se volverá negativo y no mayor quej
cualquier otro, ya sea que imprima y o no.Puede simplemente cambiar el valor de
y
a100000
e imprimiry
en el ciclo y el ciclo se romperá muy pronto.La razón por la que sientes que se volvió infinito es que
System.out.println(y);
hizo que el código se ejecutara mucho más lento que sin ninguna acción.fuente
Problema interesante En realidad, en ambos casos, el bucle no es interminable
Pero la principal diferencia entre ellos es cuándo terminará y cuánto tiempo
x
llevará exceder elint
valor máximo , que es2,147,483,647
después de que alcanzará el estado de desbordamiento y el ciclo terminará.La mejor manera de comprender este problema es probar un ejemplo simple y conservar sus resultados.
Ejemplo :
Salida:
Después de probar este bucle infinito, tardará menos de 1 segundo en terminar.
Salida:
En este caso de prueba, notará una gran diferencia en el tiempo necesario para finalizar y finalizar la ejecución del programa.
Si no tiene paciencia, pensará que este ciclo es interminable y no terminará, pero de hecho tomará horas terminar y alcanzar el estado de desbordamiento en el
i
valor.Finalmente, concluimos, después de poner la declaración de impresión dentro del bucle for, que tomará mucho más tiempo que el bucle en el primer caso sin la declaración de impresión.
El tiempo necesario para ejecutar el programa depende de las especificaciones de su computadora, en particular la potencia de procesamiento (capacidad del procesador), el sistema operativo y su IDE que está compilando el programa.
Pruebo este caso en:
Lenovo Intel Core i5 de 2,7 GHz
SO: Windows 8.1 64x
IDE: NetBeans 8.2
Se tarda unas 8 horas (486 minutos) en finalizar el programa.
También puede notar que el incremento de paso en el ciclo for
i = i + 1
es un factor muy lento para alcanzar el valor máximo de int.Podemos cambiar este factor y hacer que el incremento de pasos sea más rápido para probar el bucle en menos tiempo.
si lo ponemos
i = i * 10
y lo probamos:Salida:
Como ves, es muy rápido en comparación con el ciclo anterior.
toma menos de 1 segundo terminar y terminar de ejecutar el programa.
Después de este ejemplo de prueba, creo que debería aclarar el problema y probar la validez de Zbynek Vyskovsky: la respuesta de kvr000 , también será la respuesta a esta pregunta .
fuente