java for-loop infinite-loop

java - El ciclo aparentemente interminable termina, a menos que se use System.out.println



for-loop infinite-loop (6)

Tenía un código simple que se suponía que era un bucle sin fin, ya que x siempre crecerá 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 tal como está, imprime y y no se repite sin parar. 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 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 al método en la segunda para que se comporte como se espera? Confundido :)


Ambos ejemplos no son infinitos.

El problema es la limitación del tipo int en Java (o casi cualquier otro lenguaje común). Cuando el valor de x alcanza 0x7fffffff , al agregar cualquier valor positivo se producirá un desbordamiento y la x se volverá negativa, por lo tanto, menor que j .

La diferencia entre el primer y el segundo bucle es que el código interno lleva mucho más tiempo y probablemente tomará varios minutos hasta que x desborde. Para el primer ejemplo, puede llevar menos de un segundo o muy probablemente el optimizador eliminará 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 amortigua la salida, ya sea que salga al emulador de terminal, etc., por lo que puede ser mucho mayor que unos pocos minutos.


Ambos no son bucles sin fin, inicialmente j = 0, siempre que j <x, j aumente (j ++) y j sea un 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 eso ocurre cuando el resultado de una operación aritmética, como la multiplicación o la suma, excede el tamaño máximo del tipo entero utilizado para almacenarlo). Para el segundo ejemplo, el sistema simplemente imprime el valor de y hasta que el bucle se rompe.

si está buscando un ejemplo de un bucle sin fin, debería verse así

int x = 6; for (int i = 0; x < 10; i++) { System.out.println("Still Looping"); }

porque (x) nunca alcanzaría el valor de 10;

También puede crear un bucle infinito con un doble bucle for:

int i ; for (i = 0; i <= 10; i++) { for (i = 0; i <= 5; i++){ System.out.println("Repeat"); } }

este bucle es infinito porque el primer bucle for dice i <10, lo cual es cierto, por lo que pasa al segundo bucle for y el segundo bucle for aumenta el valor de (i) hasta que sea == 5. Luego pasa al primer for loop nuevamente porque i <10, el proceso se repite porque se restablece después del segundo for loop


Como se declaran como int, una vez que alcanza el valor máximo, el bucle se interrumpirá a medida que el valor x se vuelva negativo.

Pero cuando se agrega System.out.println al bucle, la velocidad de ejecución se hace 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 bucle) se ejecute durante el tiempo suficiente, debería tener el mismo comportamiento que el primero (el que no tiene syso dentro del bucle).


Es un bucle finito porque una vez que el valor de x excede de 2,147,483,647 (que es el valor máximo de un int ), x se volverá negativo y no será mayor que j , ya sea que imprima y o no.

Puede cambiar el valor de y a 100000 e imprimir y en el bucle y el bucle se romperá muy pronto.

La razón por la que siente 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.


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 tardará x en exceder el valor int máximo, que es 2,147,483,647 después de eso alcanzará el estado de desbordamiento y el ciclo terminará.

La mejor manera de comprender este problema es probar un ejemplo simple y preservar sus resultados.

Ejemplo :

for(int i = 10; i > 0; i++) {} System.out.println("finished!");

Salida:

finished! BUILD SUCCESSFUL (total time: 0 seconds)

Después de probar este bucle infinito, tomará menos de 1 segundo terminar.

for(int i = 10; i > 0; i++) { System.out.println("infinite: " + i); } System.out.println("finished!");

Salida:

infinite: 314572809 infinite: 314572810 infinite: 314572811 . . . infinite: 2147483644 infinite: 2147483645 infinite: 2147483646 infinite: 2147483647 finished! BUILD SUCCESSFUL (total time: 486 minutes 25 seconds)

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

Finalmente concluimos después de poner la declaración de impresión dentro del ciclo que tomará mucho más tiempo que el ciclo 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 2.7 GHz Intel Core i5

SO: Windows 8.1 64x

IDE: NetBeans 8.2

Se requieren aproximadamente 8 horas (486 minutos) para 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 int máximo.

Podemos cambiar este factor y hacer que el incremento de pasos sea más rápido para probar el bucle en menos tiempo.

si ponemos i = i * 10 y lo probamos:

for(int i = 10; i > 0; i*=10) { System.out.println("infinite: " + i); } System.out.println("finished!");

Salida:

infinite: 100000 infinite: 1000000 infinite: 10000000 infinite: 100000000 infinite: 1000000000 infinite: 1410065408 infinite: 1215752192 finished! BUILD SUCCESSFUL (total time: 0 seconds)

Como ves, es muy rápido en comparación con el ciclo anterior

Se tarda menos de 1 segundo en finalizar y finalizar la ejecución del programa.

Después de este ejemplo de prueba, creo que debería aclarar el problema y demuestra la validez de Zbynek Vyskovsky - la respuesta de kvr000 , también será la respuesta a esta question .


Puede haber dos razones para esto:

  1. Java optimiza el bucle for y dado que no hay uso de x después del bucle, simplemente elimina el bucle. Puede verificar esto poniendo System.out.println(x); declaración después del bucle.

  2. Es posible que Java no esté realmente optimizando el ciclo y esté ejecutando el programa correctamente y eventualmente x crecerá demasiado para int y overflow. El desbordamiento de enteros probablemente hará que el entero x sea ​​negativo, que será más pequeño que j, por lo que saldrá del bucle e imprimirá el valor de y . Esto también se puede verificar agregando System.out.println(x); Después del bucle.

Además, incluso en el primer caso, eventualmente se producirá un desbordamiento, lo que lo llevará al segundo caso, por lo que nunca será un verdadero bucle sin fin.