Division par zéro en Java: exception, infini ou pas un nombre

1. Vue d'ensemble

La division par zéro est une opération qui n'a pas de signification en arithmétique ordinaire et n'est donc pas définie. En programmation, cependant, si elle est souvent associée à une erreur, ce n'est pas toujours le cas .

Dans cet article, nous allons découvrir ce qui se passe lorsqu'une division par zéro se produit dans un programme Java.

Selon la spécification Java de l'opération de division, nous pouvons identifier deux cas différents de division par zéro: les entiers et les nombres à virgule flottante.

2. Entiers

Premièrement, pour les nombres entiers, les choses sont assez simples. Diviser un entier par zéro entraînera une ArithmeticException :

assertThrows(ArithmeticException.class, () -> { int result = 12 / 0; });
assertThrows(ArithmeticException.class, () -> { int result = 0 / 0; });

3. Types à virgule flottante

Cependant, lorsqu'il s'agit de nombres à virgule flottante , une exception ne sera pas levée :

assertDoesNotThrow(() -> { float result = 12f / 0; });

Afin de gérer de tels cas, Java utilise des valeurs numériques spéciales pouvant représenter les résultats d'une telle opération: NaN , POSITIVE_INFINITY et NEGATIVE_INFINITY.

3.1. NaN

Commençons par diviser les valeurs nulles en virgule flottante par zéro :

assertEquals(Float.NaN, 0f / 0); assertEquals(Double.NaN, 0d / 0);

Le résultat dans ces cas est NaN (pas un nombre).

3.2. Infini

Ensuite, divisons certaines valeurs non nulles par zéro :

assertEquals(Float.POSITIVE_INFINITY, 12f / 0); assertEquals(Double.POSITIVE_INFINITY, 12d / 0); assertEquals(Float.NEGATIVE_INFINITY, -12f / 0); assertEquals(Double.NEGATIVE_INFINITY, -12d / 0);

Comme on peut le voir, le résultat est INFINITY, avec le signe dépendant du signe des opérandes.

De plus, nous pouvons également utiliser le concept de zéro négatif pour arriver à NEGATIVE_INFINITY :

assertEquals(Float.NEGATIVE_INFINITY, 12f / -0f); assertEquals(Double.NEGATIVE_INFINITY, 12f / -0f);

3.3. Représentation de la mémoire

Alors, pourquoi la division entière par zéro lève-t-elle une exception, alors que la division en virgule flottante par zéro ne le fait pas?

Regardons cela du point de vue de la représentation de la mémoire. Pour les entiers, il n'y a pas de modèle de bits qui peut être utilisé pour stocker le résultat d'une telle opération, tandis que les nombres à virgule flottante ont des valeurs comme NaN ou INFINITY à utiliser dans des cas comme ceux-ci.

Maintenant, considérons la représentation binaire d'un flottant comme S EEEEEEE E FFFFFFF FFFFFFFF FFFFFFFF avec un bit (S) pour le signe, 8 bits (E) pour l'exposant et le reste (F) pour la mantisse.

Dans chacune des trois valeurs NaN , POSITIVE_INFINITY et NEGATIVE_INFINITY, tous les bits de la partie exposant sont mis à 1.

INFINITY a les bits de mantisse tous mis à 0, tandis que NaN a une mantisse non nulle:

assertEquals(Float.POSITIVE_INFINITY, Float.intBitsToFloat(0b01111111100000000000000000000000)); assertEquals(Float.NEGATIVE_INFINITY, Float.intBitsToFloat(0b11111111100000000000000000000000)); assertEquals(Float.NaN, Float.intBitsToFloat(0b11111111100000010000000000000000)); assertEquals(Float.NaN, Float.intBitsToFloat(0b11111111100000011000000000100000));

4. Résumé

Pour résumer, dans cet article, nous avons vu comment la division par zéro fonctionne en Java.

Des valeurs telles que INFINITY et NaN sont disponibles pour les nombres à virgule flottante mais pas pour les entiers . Par conséquent, diviser un entier par zéro entraînera une exception. Cependant, pour un float ou un double , Java autorise l'opération.

Le code complet est disponible à l'adresse over sur GitHub.