Rozważmy następującą pętlę, w której i jest jak dotąd niezadeklarowany:
while (i == i + 1) {}
Znajdź definicję i
, która poprzedza tę pętlę, taką, że pętla while trwa wiecznie.
Następne pytanie, które zadawało to samo pytanie dla tego fragmentu kodu:
while (i != i) {}
było dla mnie oczywiste. Oczywiście w tej innej sytuacji tak jest, NaN
ale naprawdę utknąłem w poprzedniej. Czy ma to związek z przepełnieniem? Co spowodowałoby, że taka pętla zapętla się na zawsze w Javie?
.equals()
metody? Ponieważ i jest niezadeklarowany, możemy użyć dowolnej klasy tego, co chcemy.null
, ponieważnull == null
jest prawdziwe inull + 1
jestnull
.0.2 + 0.1 == 0.3
zmienia jego wartość w zależności od ustawień kompilatora, fazy księżyca i tak dalej.Odpowiedzi:
Po pierwsze, ponieważ
while (i == i + 1) {}
pętla nie zmienia wartościi
, uczynienie tej pętli nieskończoną jest równoznaczne z wybraniem wartości,i
która spełniai == i + 1
.Takich wartości jest wiele:
Zacznijmy od „egzotycznych”:
lub
Przyczyna spełnienia tych wartości
i == i + 1
została podana wJLS 15.18.2. Operatory addytywne (+ i -) dla typów liczbowych :
Nie jest to zaskakujące, ponieważ dodanie skończonej wartości do nieskończonej wartości powinno dać nieskończoną wartość.
To powiedziawszy, większość wartości
i
tego spełnieniai == i + 1
to po prostu dużedouble
(lubfloat
) wartości:Na przykład:
lub
lub
double
Ifloat
typy mają ograniczoną dokładność, więc jeśli wziąć tyle dużadouble
lubfloat
wartość, dodając1
do niego spowoduje taką samą wartość.źródło
(double)(1L<<53)
- lubfloat i = (float)(1<<24)
Te łamigłówki zostały szczegółowo opisane w książce „Java Puzzlers: Traps, Pitfalls and Corner Cases” autorstwa Joshua Blocha i Neala Gaftera.
lub:
oba spowodują nieskończoną pętlę, ponieważ dodanie
1
do wartości zmiennoprzecinkowej, która jest wystarczająco duża, nie zmieni tej wartości, ponieważ nie „wypełnia luki” do jej następcy 1 .Uwaga dotycząca drugiej zagadki (dla przyszłych czytelników):
również skutkuje nieskończoną pętlą, ponieważ NaN nie jest równe żadnej wartości zmiennoprzecinkowej, w tym sobie 2 .
1 - Java Puzzlers: Traps, Pitfalls i Corner Cases (rozdział 4 - Loopy Puzzlers).
2 - JLS §15.21.1
źródło
double i = Double.POSITIVE_INFINITY;
źródło
Tylko pomysł: a co z wartościami logicznymi?
Czy to nie jest przypadek, w którym
i + 1 == i
?źródło
+
operatora przyjmującego operandy aboolean
i anint
jako).