70 votes

Pourquoi la division par zéro avec des nombres en virgule flottante (ou en double précision) ne provoque-t-elle pas une exception java.lang.ArithmeticException ? / par zéro en Java

La déclaration suivante lance java.lang.ArithmeticException: / by zero comme une évidence.

System.out.println(0/0);

parce que le littéral 0 est considéré comme un int et la division par zéro n'est pas autorisée dans l'arithmétique des nombres entiers.

Toutefois, le cas suivant n'a pas lancer toute exception comme java.lang.ArithmeticException: / by zero .

int a = 0;
double b = 6.199;
System.out.println((b/a));

Il affiche Infinity .

L'instruction suivante produit NaN (Not a Number) sans exception.

System.out.println(0D/0); //or 0.0/0, or 0.0/0.0 or 0/0.0 - floating point arithmetic.

Dans ce cas, les deux opérandes sont considérés comme des doubles.


De même, les déclarations suivantes Ne le fais pas. lancer une exception.

double div1 = 0D/0; //or 0D/0D
double div2 = 0/0D; //or 0D/0D

System.out.printf("div1 = %s : div2 = %s%n", div1, div2);
System.out.printf("div1 == div2 : %b%n", div1 == div2);
System.out.printf("div1 == div1 : %b%n", div1 == div1);
System.out.printf("div2 == div2 : %b%n", div2 == div2);
System.out.printf("Double.NaN == Double.NaN : %b%n", Double.NaN == Double.NaN);
System.out.printf("Float.NaN == Float.NaN : %b%n", Float.NaN == Float.NaN);

Ils produisent le résultat suivant.

div1 = NaN : div2 = NaN
div1 == div2 : false
div1 == div1 : false
div2 == div2 : false
Double.NaN == Double.NaN : false
Float.NaN == Float.NaN : false

Ils reviennent tous false. Pourquoi cette opération (division par zéro) est-elle autorisée avec des nombres en virgule flottante ou en double précision ?


Par ailleurs, je peux comprendre que les nombres à virgule flottante (nombres à double précision) ont leurs valeurs qui représentent infinité positive , infinité négative , pas un numéro ( NaN )...

0 votes

Dans le premier cas, puisque vous utilisez un int, la promotion pourrait donner quelque chose comme 0,00 001, ou quelque chose de proche de Double.MIN_VALUE, qui donnerait un nombre énorme si vous divisez n'importe quoi par lui.

4 votes

@Tiny : Retournez votre question : pourquoi 1/0 lancer une exception au lieu de retourner Infinity ? La réponse est qu'un entier complémentaire à deux (ce qui est le cas de l'entier de Java) n'est pas un nombre entier. int est) n'a pas de bits disponibles pour stocker des valeurs spéciales telles que Infinity o NaN Le résultat n'étant pas représentable dans le type souhaité, une exception doit être levée. Les nombres à virgule flottante n'ont pas ce problème (il existe un modèle de bit disponible pour les nombres à virgule flottante). Infinity ), et donc aucune exception n'est nécessaire.

65voto

Bill the Lizard Points 147311

En bref, c'est la façon dont c'est spécifié dans la norme IEEE-754, qui est ce que la norme Java Opérations en virgule flottante sont basés sur.

Pourquoi la division par zéro (ou par débordement, ou par sous-débordement) n'arrête-t-elle pas le programme ou ne déclenche-t-elle pas une erreur ? Pourquoi une norme sur les nombres inclut-elle "not-a-number" (NaN) ?

Le modèle 754 encourage les programmes robustes. Il est destiné non seulement aux analystes numériques mais aussi aux utilisateurs de tableurs, de systèmes de base de données ou même de cafetières. Les règles de propagation pour les NaN et les infinis permettent aux exceptions sans conséquence de disparaître. De même, le débordement progressif maintient les propriétés d'erreur sur toute l'étendue d'une précision.

Lorsque des situations exceptionnelles nécessitent une attention particulière, elles peuvent être examinées immédiatement via des trappes ou à un moment opportun via des drapeaux d'état. Les pièges peuvent être utilisés pour arrêter un programme, mais les situations irrécupérables sont extrêmement rares. L'arrêt pur et simple d'un programme n'est pas une option pour les systèmes embarqués ou les agents de réseau. Le plus souvent, les traps enregistrent des informations de diagnostic ou substituent des résultats valides.

Les drapeaux offrent à la fois un flux de contrôle prévisible et de la rapidité. Leur utilisation exige que le programmeur soit conscient des conditions exceptionnelles, mais l'adhérence des drapeaux permet aux programmeurs de retarder la gestion des conditions exceptionnelles jusqu'à ce que cela soit nécessaire.

19voto

Alnitak Points 143355

C'est ainsi parce que c'est ainsi que l'IEEE 754 l'a défini.

La division par un point flottant 0,0 donne NaN ou +/-Inf, selon que le numérateur est 0 ou non.

La division par un entier 0 n'est pas couverte par la norme IEEE 754, et génère une exception - il n'y a pas d'autre moyen d'indiquer l'erreur car un int ne peut pas représenter NaN o Inf .

La génération d'une exception est similaire à la méthode (logiciel) INT généré par une division par zéro sur les microprocesseurs x86.

11voto

Mukul Goel Points 3681

Jusqu'à l'infini et au-delà

class DoubleDivision {

    public static void main(String[] args) {
        System.out.println(5.0/0.0);
    }
}

Le code ci-dessus, et les extraits que vous avez mentionnés donnent infinity .

Pourquoi Java utilise Double pour représenter les décimales. Le binaire ne peut pas représenter complètement un nombre, il ne peut représenter qu'une approximation et, par conséquent, le double de Java non plus.

Imaginez un nombre incroyablement proche de zéro. Si vous connaissez les calculs, imaginez une limite à zéro. La variable s'approcherait de zéro à une distance imaginablement minuscule, mais ne serait jamais exactement égale. Vous pouvez imaginer cela, non ? Eh bien, supposons que ce nombre nécessite tellement de précision pour que Java puisse le représenter qu'il abandonne et l'appelle "zéro". 0.0 parce qu'il n'y a pas de bonne alternative. C'est ce qui se passe ici. Tout nombre régulier divisé par un nombre très proche de zéro est en fait l'infini. . Essayez-le : 5 / (10^-100) .

Consultez également la section : Valeurs spéciales en virgule flottante à l'adresse Erreurs mathématiques pour plus d'informations :)

Question connexe : Pourquoi 1/0 donne une erreur alors que 1.0/0/0 donne un résultat inf.

UPDATE : INT n'a pas d'infini et NaN valeur dans l'ensemble alors que le flottant a une valeur infinie et NaN valeur. (Selon les normes IEEE 754 que java suit)

6 votes

Le binaire ne peut pas représenter complètement un nombre, il ne peut représenter qu'une approximation et, par conséquent, le double de Java non plus. Un zéro est entièrement représentable dans (n'importe quelle ?) notation à virgule flottante.

1 votes

Pour les flottants/doubles selon IEEE 754, il existe un +0 et un -0, nous utilisons 0.0 pour représenter mais en fait c'est une simplification/approximation de 1/+-infinity qui, comme nous le savons tous, n'est pas 0 mais les approches 0 . c'est pourquoi j'ai dit que 0 n'est pas entièrement représentable . Je suppose qu'une bonne discussion en ressort :-)

0 votes

Le point de mon commentaire est que, bien que la division par zéro puisse ne pas être bien définie (d'un point de vue mathématique strict), et que certaines fractions puissent être impossibles à représenter, cela peut être le cas avec javas double... mais zéro est défini et 0.0 == 0 comme vous l'attendez. Donc le problème est la division, pas le zéro. Je n'ai pas voté contre vous, quelqu'un d'autre l'a fait.

5voto

Raedwald Points 8862

Lorsqu'il y a une division par zéro, l'ordinateur ne peut pas créer une représentation du résultat sous forme de nombre. L'ordinateur doit signaler que le résultat n'est pas un nombre.

Pour les valeurs à virgule flottante, il peut produire une valeur sentinelle spéciale qui n'est pas un nombre, parce qu'il y a des valeurs de 32 bits (pour float ) et 64 bits (pour double ) qui ne représentent pas un nombre, et peuvent donc être interprétés comme des motifs non numériques ( NaN ).

Pour les valeurs entières utilisant le schéma commun de complémentation à deux (comme l'exige Java), toutes les valeurs de 32 bits (pour les valeurs de int ) et 64 bits (pour long ) représentent un nombre. L'ordinateur ne peut donc pas signaler le problème en utilisant une sentinelle. Il doit signaler le problème "hors bande" d'une manière ou d'une autre. Lancer une exception est la méthode hors bande choisie par Java.

4voto

Peter Lawrey Points 229686

Java suit la norme IEEE 754 qui définit les valeurs à retourner par défaut dans le cas d'une division par zéro. http://en.wikipedia.org/wiki/IEEE_754#Exception_handling

Division par zéro (une opération sur des opérandes finis donne un résultat infini exact, par exemple, 1/0 ou log(0)). (renvoie ±infini par défaut).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X