Ich hatte ein einfaches Stück Code, das eigentlich eine Endlosschleife sein sollte, da x
es immer größer wird und immer größer bleibt als j
.
int x = 5;
int y = 9;
for (int j = 0; j < x; j++) {
x = x + y;
}
System.out.println(y);
aber so wie es ist, wird es gedruckt y
und nicht endlos wiederholt. Ich kann nicht herausfinden warum. Wenn ich den Code jedoch folgendermaßen anpasse:
int x = 5;
int y = 9;
for (int j = 0; j < x; j++) {
x = x + y;
System.out.println(y);
}
System.out.println(y);
Es wird eine Endlosschleife und ich habe keine Ahnung warum. Erkennt Java eine Endlosschleife und überspringt sie in der ersten Situation, muss aber in der zweiten einen Methodenaufruf ausführen, damit sie sich wie erwartet verhält? Verwirrt :)
java
for-loop
infinite-loop
Omar
quelle
quelle
x
wächst als die Schleifenvariable . Mit anderen Worten, wird niemals eine Obergrenze erreichen, daher wird die Schleife "für immer" laufen. Nun, nicht für immer, Sie werden höchstwahrscheinlich irgendwann einen Überlauf bekommen.j
j
y
238609294 MalSystem.out.println(x)
statty
am Ende sofort gezeigt, was das Problem warAntworten:
Beide Beispiele sind nicht endlos.
Das Problem ist die Einschränkung des
int
Typs in Java (oder so ziemlich jeder anderen gängigen Sprache). Wenn der Wert vonx
erreicht0x7fffffff
, führt das Hinzufügen eines positiven Werts zu einem Überlauf und der Wertx
wird negativ, daher niedriger alsj
.Der Unterschied zwischen der ersten und der zweiten Schleife besteht darin, dass der innere Code viel mehr Zeit benötigt und es wahrscheinlich einige Minuten dauern würde, bis er
x
überläuft. Im ersten Beispiel kann es weniger als eine Sekunde dauern, oder der Code wird höchstwahrscheinlich vom Optimierer entfernt, da er keine Auswirkungen hat.Wie in der Diskussion erwähnt, hängt die Zeit stark davon ab, wie das Betriebssystem die Ausgabe puffert, ob sie an den Terminalemulator usw. ausgegeben wird, sodass sie viel höher als einige Minuten sein kann.
quelle
println()
unter Windows ist eine Blockierungsoperation, während es unter (einigen?) Unix gepuffert ist und daher viel schneller geht. Versuchen Sie auch zu verwendenprint()
, welche Puffer, bis es ein trifft\n
(oder der Puffer füllt oderflush()
heißt)Da sie als int deklariert sind, wird die Schleife unterbrochen, sobald der Maximalwert erreicht ist, da der x-Wert negativ wird.
Wenn jedoch System.out.println zur Schleife hinzugefügt wird, wird die Ausführungsgeschwindigkeit sichtbar (da die Ausgabe an die Konsole die Ausführungsgeschwindigkeit verlangsamt). Wenn Sie jedoch das zweite Programm (das mit syso in der Schleife) lange genug laufen lassen, sollte es das gleiche Verhalten wie das erste haben (das ohne syso in der Schleife).
quelle
Dafür kann es zwei Gründe geben:
Java optimiert die
for
Schleife undx
entfernt die Schleife einfach, da sie nach der Schleife nicht verwendet wird. Sie können dies überprüfen, indem Sie eineSystem.out.println(x);
Anweisung nach der Schleife setzen.Es ist möglich, dass Java die Schleife nicht wirklich optimiert und das Programm korrekt ausführt und schließlich
x
zu groß wirdint
und überläuft. Ein Ganzzahlüberlauf macht die Ganzzahl höchstwahrscheinlichx
negativ, was kleiner als j ist, und kommt daher aus der Schleife heraus und gibt den Wert von ausy
. Dies kann auch durch HinzufügenSystem.out.println(x);
nach der Schleife überprüft werden .Selbst im ersten Fall tritt schließlich ein Überlauf auf, wodurch der zweite Fall erreicht wird, sodass es sich nie um eine echte Endlosschleife handelt.
quelle
sysout
ist so langsam, um die Illusion einer Endlosschleife hinzuzufügen.Sie sind beide keine Endlosschleifen, anfänglich j = 0, solange j <x, j zunimmt (j ++) und j eine ganze Zahl ist, so dass die Schleife laufen würde, bis sie den Maximalwert erreicht und dann überläuft (ein ganzzahliger Überlauf ist die Bedingung Dies tritt auf, wenn das Ergebnis einer arithmetischen Operation wie Multiplikation oder Addition die maximale Größe des zum Speichern verwendeten Ganzzahltyps überschreitet.). Im zweiten Beispiel gibt das System nur den Wert von y aus, bis die Schleife unterbrochen wird.
Wenn Sie nach einem Beispiel für eine Endlosschleife suchen, sollte es so aussehen
weil (x) niemals den Wert 10 erreichen würde;
Sie können auch eine Endlosschleife mit einer doppelten for-Schleife erstellen:
Diese Schleife ist unendlich, weil die erste for-Schleife i <10 sagt, was wahr ist, so dass sie in die zweite for-Schleife geht und die zweite for-Schleife den Wert von (i) erhöht, bis sie == 5 ist. Dann geht sie in die erste über for-Schleife erneut, da i <10 ist, wiederholt sich der Prozess immer wieder, da er nach der zweiten for-Schleife zurückgesetzt wird
quelle
Es ist eine endliche Schleife, denn sobald der Wert von
x
überschreitet2,147,483,647
(was der Maximalwert von a istint
),x
wird er negativ und nicht größer alsj
jeder andere, unabhängig davon, ob Sie y drucken oder nicht.Sie können einfach den Wert von
y
to ändern100000
undy
in der Schleife drucken , und die Schleife wird sehr bald unterbrochen.Der Grund, warum Sie das Gefühl haben, dass es unendlich wird, ist, dass der
System.out.println(y);
Code sehr viel langsamer ausgeführt wird als ohne Aktionen.quelle
Interessantes Problem In beiden Fällen ist die Schleife nicht endlos
Der Hauptunterschied zwischen ihnen besteht jedoch darin, wann sie beendet werden und wie viel Zeit benötigt
x
wird, um denint
Maximalwert zu überschreiten. Danach2,147,483,647
erreicht sie den Überlaufzustand und die Schleife endet.Der beste Weg, um dieses Problem zu verstehen, besteht darin, ein einfaches Beispiel zu testen und die Ergebnisse beizubehalten.
Beispiel :
Ausgabe:
Nach dem Testen dieser Endlosschleife dauert das Beenden weniger als 1 Sekunde.
Ausgabe:
In diesem Testfall werden Sie einen großen Unterschied in der Zeit feststellen, die zum Beenden und Beenden des Programms benötigt wird.
Wenn Sie nicht geduldig sind, werden Sie denken, dass diese Schleife endlos ist und nicht beendet wird, aber tatsächlich wird es Stunden dauern, bis sie beendet ist und den Überlaufzustand bei
i
Wert erreicht.Nachdem wir die print-Anweisung in die for-Schleife eingefügt haben, haben wir schließlich festgestellt, dass es im ersten Fall ohne print-Anweisung viel länger dauert als die Schleife.
Die zum Ausführen des Programms benötigte Zeit hängt von Ihren Computerspezifikationen ab, insbesondere von der Verarbeitungsleistung (Prozessorkapazität), dem Betriebssystem und Ihrer IDE, die das Programm kompiliert.
Ich teste diesen Fall auf:
Lenovo 2,7 GHz Intel Core i5
Betriebssystem: Windows 8.1 64x
IDE: NetBeans 8.2
Das Beenden des Programms dauert ca. 8 Stunden (486 Minuten).
Sie können auch feststellen, dass das Schrittinkrement in der for-Schleife
i = i + 1
ein sehr langsamer Faktor ist, um den maximalen int-Wert zu erreichen.Wir können diesen Faktor ändern und das Schrittinkrement beschleunigen, um die Schleife in kürzerer Zeit zu testen.
wenn wir es setzen
i = i * 10
und testen:Ausgabe:
Wie Sie sehen, ist es im Vergleich zur vorherigen Schleife sehr schnell
Das Beenden und Beenden des Programms dauert weniger als 1 Sekunde.
Nach diesem Testbeispiel sollte es meines Erachtens das Problem klären und die Gültigkeit der Antwort von Zbynek Vyskovsky - kvr000 beweisen . Auch diese Frage wird beantwortet .
quelle