J'ai couru ce casse-tête d'un cours de programmation avancé à un examen universitaire britannique .
Considérez la boucle suivante, dans laquelle i est, jusqu'à présent, non déclarée:
while (i == i + 1) {}
Trouvez la définition de i
, qui précède cette boucle , de sorte que la boucle while continue à jamais.
La question suivante, qui posait la même question pour cet extrait de code:
while (i != i) {}
était évident pour moi. Bien sûr, dans cet autre cas, c'est NaN
mais je suis vraiment bloqué sur le précédent. Est-ce que cela a à voir avec un débordement? Qu'est-ce qui ferait en boucle une telle boucle pour toujours en Java?
Tout d'abord, comme la boucle while (i == i + 1) {}
ne modifie pas la valeur de i
, l'infini de cette boucle revient à choisir une valeur de i
satisfaisante pour i == i + 1
.
Il y a beaucoup de telles valeurs:
Commençons par les "exotiques":
double i = Double.POSITIVE_INFINITY;
ou
double i = Double.NEGATIVE_INFINITY;
La raison pour laquelle ces valeurs satisfont i == i + 1
est indiquée dans
JLS 15.18.2. Opérateurs additifs (+ et -) pour les types numériques :
La somme d'un infini et d'une valeur finie est égale à l'opérande infini.
Cela n’est pas surprenant, car l’ajout d’une valeur finie à une valeur infinie devrait donner une valeur infinie.
Cela dit, la plupart des valeurs de i
qui satisfont i == i + 1
sont simplement grandes double
(ou float
):
Par exemple:
double i = Double.MAX_VALUE;
ou
double i = 1000000000000000000.0;
ou
float i = 1000000000000000000.0f;
Les types double
et float
ont une précision limitée. Par conséquent, si vous prenez une valeur assez grande de double
ou float
, l'ajout de 1
donnera le même résultat. valeur.
Ces casse-têtes sont décrits en détail dans le livre "Les casse-têtes Java: pièges, pièges et angles" de Joshua Bloch et Neal Gafter.
double i = Double.POSITIVE_INFINITY;
while (i == i + 1) {}
ou:
double i = 1.0e40;
while (i == i + 1) {}
les deux aboutiront à une boucle infinie, car ajouter 1
à une valeur en virgule flottante suffisamment grande ne changera pas la valeur, car elle ne "comble pas l'écart" avec son successeur1.
Une note sur le deuxième casse-tête (pour les futurs lecteurs):
double i = Double.NaN;
while (i != i) {}
entraîne également une boucle infinie, car NaN n'est égal à aucune valeur en virgule flottante, y compris lui-même 2.
1 - Java Puzzlers: pièges, pièges et autres cas (chapitre 4 - Loopy Puzzlers).
2 - JLS §15.21.1
double i = Double.POSITIVE_INFINITY;
Juste une idée: qu'en est-il des booléens?
bool i = TRUE;
N'est-ce pas un cas où i + 1 == i
?