5
votes

Division par zéro en C

Quand je compile le programme:

#include <stdio.h>

int main(void)
{
    double x, y = 0;

    x = 1 / y;
    printf("x = %f\n", x);
    return 0;
}

Cela donne une "exception à virgule flottante (core dumped)"

Cependant, quand je compile:

#include <stdio.h>

int main(void)
{
    int x, y = 0;

    x = 1 / y;
    printf("x = %d\n", x);
    return 0;
}

Il affiche "x = inf"

Pourquoi renvoie x comme une valeur infinie si vous utilisez double mais renvoie une erreur si vous utilisez int?


7 commentaires

Les entiers n'ont pas de inf ou NaN .


La division entière déclenche une exception de processeur, tandis que la division en virgule flottante a une représentation.


Une question connexe stackoverflow .com / questions / 23878400 /…


@WeatherVane - très belle nouvelle icône / avatar ...


@ DavidC.Rankin vous avez l'air plutôt bien vous-même!


La raison principale est que 1/0 => Inf est mathématiquement incorrect, mais les nombres à virgule flottante sont des valeurs inexactes et il se peut que dans vos calculs, le diviseur soit tellement petit qu'il ait été arrondi à 0, il est donc toujours préférable de produire un résultat plutôt que de simplement planter tout le programme pour que vous sachiez où il s'est mal passé. Et c'est ce que fait IEEE 754 dans la plupart des cas. Cependant, ce n'est pas une chose sensée à faire avec les entiers, et les entiers ne peuvent pas représenter l'infini.


Notez que vous pouvez déjà obtenir l'infini avec 1 / 1e-309 , qui est de plusieurs ordres de grandeur plus petit que l'infini mathématique ;-)


3 Réponses :


4
votes

Une variable à virgule flottante peut en fait stocker une valeur représentant l'infini. (C'est la valeur INFINITY définie dans math.h.) Mais il n'y a pas de représentation entière de l'infini, donc la seule chose à faire est d'échouer.


15 commentaires

Ce n'est pas la seule chose à faire. Il peut arriver des choses infinies, comme des démons peuvent surgir de votre nez .


Il vaut probablement la peine de souligner que l'infini n'est pas le résultat mathématiquement correct de la division d'un nombre par zéro - au contraire, le résultat est mathématiquement indéfini.


@JeremyFriesner: True, mais la norme à virgule flottante IEEE spécifie Infinity comme résultat de la division par zéro (pour certains paramètres). Une implémentation C peut être conforme ou non à IEEE.


@JeremyFriesner: 1.0 / 0.0 ne devrait-il pas être NaN alors? L'infini entre en jeu lorsque vous prenez une limite de 1.0 / * x * car x tend vers 0 depuis la gauche (- ∞) ou la droite (+ ().


@jxh: stackoverflow.com/q/14682005/827263 traite des règles IEEE pour la division par zéro.


Pas dans un processeur débutant, ce qui prendrait un temps infini à le calculer par soustraction.


@JeremyFriesner: Il n'y a pas de définition unique de l'arithmétique. L'arithmétique découle des axiomes, et différents systèmes d'arithmétique conviennent à des fins différentes,


"donc la seule chose à faire est d'échouer."; en fait non - le comportement est indéfini, et on ne peut pas se fier au fait qu '"il échoue" (quel que soit le sens "échec").


@StephanLechner en fait IEEE est plus applicable ici que la norme C.


@P__J__: L'ingénierie n'est pas un processus consistant à deviner quelles spécifications s'appliquent. Ils doivent être énoncés explicitement et, idéalement, une conception correcte avec le comportement souhaité est logiquement dérivée des spécifications. Cette question est étiquetée C et non IEEE-754, ce qui nous dit: «Cette balise doit être utilisée avec des questions générales concernant le langage C, tel que défini dans la norme ISO 9899 (la dernière version, 9899: 2018, sauf indication contraire - également balise demandes spécifiques à la version avec c89, c99, C11, etc.). » Nous préférons donc la norme C comme base de réponse.


D'accord, le résultat de la division d'un entier par zéro en C est techniquement indéfini, mais il est assez évident que sur la machine de l'OP, il produit une erreur. Le PO a demandé pourquoi il générait l'erreur, pas s'il pouvait se fier à ce comportement.


@EricPostpischil n'était pas d'accord. Tout le matériel mathématique et les logiciels de bibliothèque sont conformes à l'IEEE et non à la norme. Si


@P__J__: Non, ils ne le font pas. Même s'ils l'ont fait, la question porte sur C, pas sur le matériel ou les bibliothèques.


@EricPostpischil cette question n'est pas possible de répondre sans prendre en compte l'implémentation. Ensuite, c'est UB qui forme le point de vue pratique ne veut rien dire quand on fait un travail numérique


@P__J__: L'idée que l'absence de réponse d'une question justifie de faire des hypothèses est absurde. Ce qui serait raisonnable, c'est de dire que C ne définit pas le comportement mais d'observer que le résultat obtenu peut être ou même probablement parce que leur implémentation utilise certaines fonctionnalités de l'IEEE 754, qui prévaut. Notez que l'utilisation de certaines fonctionnalités de IEEE 754 n'est pas la même chose que la conformité à IEEE 754 et ne suppose pas que IEEE 754 s'applique. Il donne des informations au PO qui peut les conduire à un apprentissage et une enquête plus approfondis sans affirmer des déclarations dont la véracité n'est pas connue.



8
votes

La norme C déclare explicitement que la division par zéro a un comportement indéfini pour les opérandes entiers ou flottants.

C11 6.5.5 paragraphe 5:

Le résultat de l'opérateur / est le quotient de la division du premier opérande par le second; le résultat de l'opérateur % est le reste. Dans les deux opérations, si la valeur du deuxième opérande est zéro, le comportement n'est pas défini.

Un comportement non défini signifie que la norme ne dit rien sur ce qui se passe. Cela pourrait donner un résultat significatif ou dénué de sens, il pourrait s'écraser ou, comme le dit la blague standard, faire voler des démons hors de votre nez. (Bien sûr, ce dernier ne se produira pas, mais cela ne violerait pas la norme C si c'était le cas.)

Les types à virgule flottante, contrairement aux types entiers, ont souvent des valeurs spéciales qui ne représentent pas des nombres. La norme à virgule flottante IEEE spécifie que la division par zéro peut donner un résultat Infinity, ce que fait votre implémentation. Il n'y a pas de valeur "Infinity" pour les entiers. (Notez que les implémentations C peuvent être conformes ou non à la norme IEEE à virgule flottante.)

Cette question traite de la sémantique de la division par zéro en virgule flottante IEEE.


0 commentaires

5
votes

La norme C définit que le comportement d'une division par zéro sur des opérandes de types arithmétiques n'est pas défini (cf., par exemple, ce projet de norme C en ligne):

6.5.5 Opérateurs multiplicatifs

2 Chacun des opérandes doit être de type arithmétique. Les opérandes du L'opérateur% doit être de type entier.

5 Le résultat de l'opérateur / est le quotient de la division de le premier opérande par le second; le résultat de l'opérateur% est le reste. Dans les deux opérations, si la valeur du deuxième opérande est zéro, le comportement n'est pas défini.

Et cette règle inclut explicitement les valeurs à virgule flottante, puisque le terme arithmétique types signifie valeurs intégrales et valeurs à virgule flottante:

6.2.5 Types

18 Les types entiers et flottants sont appelés collectivement arithmétique types.

Par conséquent, vos deux exemples sont en fait un comportement indéfini, et chaque compilateur peut spécifier lui-même comment traiter vos déclarations. Et donc, il est conforme à la norme si un compilateur traite la division intégrale par zéro comme une exception, alors que la division en virgule flottante par zéro donne la valeur spéciale inf . Remarque: la norme ne définit pas que cela doit être le cas.


0 commentaires