J'avais un simple morceau de code qui était censé être une boucle sans fin car il x
augmentera toujours et restera toujours plus grand que j
.
int x = 5;
int y = 9;
for (int j = 0; j < x; j++) {
x = x + y;
}
System.out.println(y);
mais tel quel, il imprime y
et ne boucle pas indéfiniment. Je ne peux pas comprendre pourquoi. Cependant, lorsque j'ajuste le code de la manière suivante:
int x = 5;
int y = 9;
for (int j = 0; j < x; j++) {
x = x + y;
System.out.println(y);
}
System.out.println(y);
Cela devient une boucle sans fin et je ne sais pas pourquoi. Java reconnaît-il sa boucle sans fin et l'ignore dans la première situation, mais doit-il exécuter un appel de méthode dans la seconde pour qu'il se comporte comme prévu? Confus :)
x
croît plus vite que la variable de bouclej
. En d'autres termes,j
n'atteindra jamais une limite supérieure, donc la boucle fonctionnera "pour toujours". Eh bien, pas pour toujours, vous aurez probablement un débordement à un moment donné.y
238609294 foisSystem.out.println(x)
au lieu dey
la fin aurait montré instantanément quel était le problèmeRéponses:
Les deux exemples ne sont pas sans fin.
Le problème est la limitation du
int
type en Java (ou à peu près dans n'importe quel autre langage courant). Lorsque la valeur dex
atteint0x7fffffff
, l'ajout d'une valeur positive entraînera un débordement et lex
deviendra négatif, donc inférieur àj
.La différence entre la première et la deuxième boucle est que le code interne prend beaucoup plus de temps et qu'il faudrait probablement plusieurs minutes avant que les
x
débordements ne se produisent . Pour le premier exemple, cela peut prendre moins d'une seconde ou très probablement le code sera supprimé par l'optimiseur car il n'a aucun effet.Comme mentionné dans la discussion, le temps dépendra fortement de la façon dont le système d'exploitation met en mémoire tampon la sortie, s'il sort vers l'émulateur de terminal, etc., de sorte qu'il peut être beaucoup plus élevé que quelques minutes.
la source
println()
sur Windows est une opération bloquante, alors que sur (certains?) Unix, il est mis en mémoire tampon, donc va beaucoup plus vite. Essayez également d'utiliserprint()
, quels tampons jusqu'à ce qu'il atteigne un\n
(ou que le tampon se remplisse, ouflush()
soit appelé)Puisqu'ils sont déclarés comme int, une fois qu'il atteint la valeur maximale, la boucle se cassera car la valeur x deviendra négative.
Mais lorsque System.out.println est ajouté à la boucle, la vitesse d'exécution devient visible (car la sortie vers la console ralentira la vitesse d'exécution). Cependant, si vous laissez le 2ème programme (celui avec syso à l'intérieur de la boucle) s'exécuter assez longtemps, il devrait avoir le même comportement que le premier (celui sans syso dans la boucle).
la source
Il peut y avoir deux raisons à cela:
Java optimise la
for
boucle et comme il n'y a aucune utilisation d'x
après la boucle, supprime simplement la boucle. Vous pouvez vérifier cela en mettant uneSystem.out.println(x);
instruction après la boucle.Il est possible que Java n'optimise pas réellement la boucle et qu'il exécute le programme correctement et finisse par
x
devenir trop volumineuxint
et déborder. Un débordement d'entier rendra probablement l'entierx
négatif qui sera plus petit que j et il sortira donc de la boucle et affichera la valeur dey
. Cela peut également être vérifié en ajoutantSystem.out.println(x);
après la boucle.De plus, même dans le premier cas, un débordement se produira éventuellement, ce qui le rendra dans le second cas, de sorte que ce ne sera jamais une véritable boucle sans fin.
la source
sysout
est si lent à ajouter l'illusion d'une boucle infinie.Ce ne sont pas tous les deux des boucles infinies, initialement j = 0, tant que j <x, j augmente (j ++), et j est un entier donc la boucle fonctionnerait jusqu'à ce qu'elle atteigne la valeur maximale puis déborde (un débordement d'entier est la condition qui se produit lorsque le résultat d'une opération arithmétique, telle que la multiplication ou l'addition, dépasse la taille maximale du type entier utilisé pour le stocker.). pour le deuxième exemple, le système imprime simplement la valeur de y jusqu'à ce que la boucle se brise.
si vous cherchez un exemple de boucle sans fin, cela devrait ressembler à ceci
car (x) n'atteindrait jamais la valeur de 10;
vous pouvez également créer une boucle infinie avec une double boucle for:
cette boucle est infinie car la première boucle for dit i <10, ce qui est vrai donc elle entre dans la deuxième boucle for et la deuxième boucle for augmente la valeur de (i) jusqu'à ce qu'elle soit == 5. Ensuite, elle passe dans la première boucle for à nouveau parce que i <10, le processus se répète car il se réinitialise après la deuxième boucle for
la source
C'est une boucle finie car une fois que la valeur de
x
dépasse2,147,483,647
(qui est la valeur maximale de anint
),x
elle deviendra négative et ne sera plusj
supérieure, que vous imprimiez y ou non.Vous pouvez simplement changer la valeur de
y
à100000
et imprimery
dans la boucle et la boucle se cassera très bientôt.La raison pour laquelle vous pensez qu'il est devenu infini est que le
System.out.println(y);
code a été exécuté beaucoup plus lentement que sans aucune action.la source
Problème intéressant En fait, dans les deux cas, la boucle n'est pas sans fin
Mais la principale différence entre eux est quand il se terminera et combien de temps
x
il faudra pour dépasser laint
valeur maximale , c'est-2,147,483,647
à-dire qu'il atteindra l'état de débordement et que la boucle se terminera.La meilleure façon de comprendre ce problème est de tester un exemple simple et de conserver ses résultats.
Exemple :
Production:
Après avoir testé cette boucle infinie, il faudra moins d'une seconde pour se terminer.
Production:
Sur ce cas de test, vous remarquerez une énorme différence dans le temps nécessaire pour terminer et terminer l'exécution du programme.
Si vous n'êtes pas patient, vous penserez que cette boucle est sans fin et ne se terminera pas, mais en fait, il faudra des heures pour se terminer et atteindre l'état de débordement à la
i
valeur.Enfin, nous avons conclu après avoir mis l'instruction print dans la boucle for que cela prendrait beaucoup plus de temps que la boucle dans le premier cas sans instruction print.
Ce temps nécessaire pour exécuter le programme dépend des spécifications de votre ordinateur, en particulier de la puissance de traitement (capacité du processeur), du système d'exploitation et de votre IDE qui compile le programme.
Je teste ce cas sur:
Lenovo 2,7 GHz Intel Core i5
Système d'exploitation: Windows 8.1 64x
IDE: NetBeans 8.2
Il faut environ 8 heures (486 minutes) pour terminer le programme.
Vous pouvez également remarquer que l'incrément de pas dans la boucle for
i = i + 1
est un facteur très lent pour atteindre la valeur max int.Nous pouvons changer ce facteur et accélérer l'incrémentation des pas afin de tester la boucle en moins de temps.
si nous le mettons
i = i * 10
et le testons:Production:
Comme vous le voyez, c'est très rapide par rapport à la boucle précédente
cela prend moins d'une seconde pour se terminer et terminer l'exécution du programme.
Après cet exemple de test, je pense qu'il devrait clarifier le problème et prouver la validité de Zbynek Vyskovsky - la réponse de kvr000 , aussi ce sera la réponse à cette question .
la source