web-dev-qa-db-fra.com

Pour quelle valeur de i fait-il while (i == i + 1) {} boucle pour toujours?

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?

118
jake mckenzie

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.

141
Eran

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

64
Oleksandr Pyrohov

double i = Double.POSITIVE_INFINITY;

1
Farcas George

Juste une idée: qu'en est-il des booléens?

bool i = TRUE;

N'est-ce pas un cas où i + 1 == i?

1
Dominique