web-dev-qa-db-fra.com

Pourquoi la division par zéro avec des nombres à virgule flottante (ou à double précision) ne renvoie-t-elle pas Java.lang.ArithmeticException:/by zero in Java

L'instruction suivante jette Java.lang.ArithmeticException: / by zero comme une évidence.

System.out.println(0/0);

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

Cependant, le cas suivant ne lance pas ne lève aucune exception telle que 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 (pas un nombre) 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 doubles.


De même, les déclarations suivantes ne pas ne lèvent aucune 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 la sortie suivante.

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

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


En passant, je peux comprendre que les nombres à virgule flottante (nombres à double précision) ont des valeurs qui représentent l'infini positif , l'infini négatif , pas un nombre (NaN ) ...

54
Tiny

En bref, c’est ce qui est spécifié dans la norme IEEE-754, sur laquelle sont basées les opérations à virgule flottante de Java.

Pourquoi la division par zéro (ou débordement ou dépassement insuffisant) n'arrête-t-elle pas le programme ou ne provoque-t-elle pas une erreur? Pourquoi une norme sur les nombres inclut-elle "non-un nombre" (NaN)?

Le modèle 754 encourage des programmes robustes. Il est destiné non seulement aux analystes numériques, mais également 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 à des exceptions sans conséquence de disparaître. De même, un dépassement progressif maintient les propriétés d'erreur sur une plage de précision.

Lorsque des situations exceptionnelles requièrent votre attention, elles peuvent être immédiatement examinées via des pièges ou à un moment opportun via des indicateurs 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 d'un programme n'est pas une option pour les systèmes intégrés ou les agents de réseau. Plus souvent, les interruptions enregistrent des informations de diagnostic ou substituent des résultats valides.

Les drapeaux offrent à la fois un flux de contrôle et une vitesse prévisibles. Leur utilisation nécessite que le programmeur soit conscient des conditions exceptionnelles, mais la rigidité du drapeau permet aux programmeurs de différer le traitement des conditions exceptionnelles jusqu'à ce que nécessaire.

54
Bill the Lizard

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

La division par un nombre à virgule flottante 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 IEEE 754 et génère une exception. Il n'y a pas d'autre moyen d'indiquer l'erreur, car int ne peut représenter NaN ou Inf.

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

15
Alnitak

Vers 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

WhyJava utilise Doubles pour représenter les nombres décimaux. 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 le calcul, imaginez une limite à zéro. La variable serait proche de zéro à une distance imaginablement minuscule mais jamais égale exactement. Vous pouvez imaginer ça, non? Eh bien, supposons que le nombre nécessite tant de précision de la part de Java, il abandonne et l'appelle 0.0 car il n'a pas de bonne alternative. C’est ce qui se passe ici. Tout nombre régulier divisé par un nombre super proche de zéro est fondamentalement infini. Essayez-le: 5 / (10^-100).

Reportez-vous également à la section: Valeurs spéciales en virgule flottante à Erreurs mathématiques pour plus d'informations :)

Question connexe: pourquoi 1/0 donne-t-il une erreur mais 1.0/0/0 donne-t-il inf

UPDATE: INT n'a pas de valeur infinie et NaN dans l'ensemble alors que float a une valeur infinie et NaN. (Selon les normes IEEE 754 suivies par Java)

11
Mukul Goel

Lorsqu'il y a une division par zéro, l'ordinateur ne peut pas créer de 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 non numérique, car il existe des modèles de bits 32 bits (pour float) et 64 bits (pour double) qui ne représentent pas un nombre et peuvent donc être interprétés. en tant que nombre non (NaN).

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

5
Raedwald

Java respecte la norme IEEE 754 qui définit les valeurs à renvoyer 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).

3
Peter Lawrey
import Java.util.Scanner;

public class Division {

    public static void main(String[] args) {
        int a, b;
        float result;

        Scanner input = new Scanner(System.in);
        System.out.println("Enter value for a : ");
        a = input.nextInt();

        System.out.println("Enter value for b : ");
        b = input.nextInt();

        try {
            /* here we used "if clause" because result will be in float
             note: Here result is in float, so JVM Cant Catch Exception.
             if we Try to Divide with Zero with Float Values It gives Output as
             Divided by Zero is Infinity */
            if (b != 0) {
                result = (float) a / b;
                System.out.println("Result of " + a + " divided by " + b + " is : " + result);
            } else // here result will be in integer so Jvm can easily Catch The Exception
            {
                result = a / b;
            }
        } catch (ArithmeticException e) {
            System.out.println("Sorry Division By Zero Is Not Possible");
        }
    }
}

/* Ouput :
Enter value for a :2
Enter value for b : 7
Result of 2 divided by 7 is : 0.2857143 */

 /* Ouput :
Enter value for a : 16
Enter value for b : 0
Sorry Division By Zero Is Not Possible */
0
sandeep16