Un ordinateur tentera-t-il de diviser par zéro?

59

Nous savons tous 0/0est Undefinedet renvoie une erreur si je devais le mettre dans une calculatrice, et si je devais créer un programme (en C au moins) le système d' exploitation devait prendre fin quand je tente de diviser par zéro.

Mais ce que je me demandais, c’est si l’ordinateur tente même de diviser par zéro ou s’il dispose simplement d’une «protection intégrée», de sorte que, lorsqu'il «voit», 0/0il renvoie une erreur avant même d’essayer de la calculer.

Ankush
la source
10
0/0 est indéfini, tout autre nombre / 0 est un type d'erreur différent, vous semblez confondre les deux
edc65
7
Tout nombre divisé par 0 est indéfini mathématiquement.
ManoDestra
12
@ jwg: "si elle avait une valeur, ce serait 1" - pas nécessairement; il y a des branches entières de mathématiques consacrées à ce que la valeur pourrait être dans des circonstances différentes :)
psmears
11
Pour clarifier la terminologie ici, 0/0 s'appelle une forme indéterminée alors que x / 0 pour x non nul est indéfini . Un calcul qui aboutit à 0/0 peut souvent être calculé de manière différente pour donner une réponse réelle, alors que x / 0 est essentiellement dépourvu de sens.
Epoque
9
@ jwg vous pourriez alors être intéressé par la règle de l'hopital. Il y a définitivement des cas où 0/0 n'implique pas une valeur de 1.
d0nut

Réponses:

74

La CPU a une détection intégrée. La plupart des architectures de jeux d'instructions spécifient que la CPU va se connecter à un gestionnaire d'exceptions pour une division entière par zéro (je ne pense pas que le fait que le dividende soit égal à zéro ne le dérange pas).

Il est possible que la vérification d'un diviseur zéro soit effectuée en parallèle dans le matériel avec la tentative de division. Cependant, la détection de la condition incriminée annule effectivement la division et les pièges. Nous ne pouvons donc pas vraiment savoir si une partie de celui-ci a tenté la division ou non.

(Le matériel fonctionne souvent ainsi, faisant plusieurs choses en parallèle et choisissant ensuite le résultat approprié, car chacune des opérations peut alors être lancée immédiatement au lieu de procéder à la sérialisation du choix de l'opération appropriée.)

Le même mécanisme d'interruption vers exception sera également utilisé lorsque la détection de dépassement de capacité est activée, ce que vous demandez habituellement en utilisant différentes instructions d'ajout / de sous / mul (ou un indicateur sur ces instructions).

La division en virgule flottante a également une détection intégrée pour la division par zéro, mais renvoie une valeur différente ( IEEE 754 spécifie NaN ) au lieu d'être capturée par un gestionnaire d'exceptions.


En théorie, si le processeur omettait de détecter une tentative de division par zéro, les problèmes pourraient inclure:

  • suspendre la CPU (par exemple dans une boucle inf.) - cela peut arriver si la CPU utilise un algorithme de division qui s’arrête lorsque le numérateur est inférieur au diviseur (en valeur absolue). Un blocage comme celui-ci compterait à peu près comme un crash du processeur.
  • une réponse erronée (éventuellement prévisible), si la CPU utilise un compteur pour terminer la division au plus grand nombre possible d'étapes de division (par exemple, 31 ou 32 sur une machine 32 bits).
Erik Eidt
la source
51
@Ankush Un "crash système" n'est pas vraiment quelque chose qui se passe au niveau du processeur. Le comportement le plus probable d'un processeur qui n'interrompt pas la division par zéro serait qu'il effectue simplement l'opération de division, produit un résultat insensé et continue. Tout comme lorsque vous ajoutez deux entiers dépassant leur capacité.
Ixrec
6
En virgule flottante, le choix entre "NaN" et "trappe" peut généralement être défini en inversant les indicateurs dans la FPU.
Vatine
10
@Ankush Au cas où ce que lxrec a dit n'était pas clair: en ce qui concerne le CPU, il n'y a pas de crash.
user253751
7
@Ankush Peu de situations provoquent une "panne système" au niveau de la CPU. Dans ces cas, nous parlons de choses comme l'arrêt de la protection thermique (protection contre la surchauffe), les triple fautes et des situations similaires. Presque tous les crashs que vous rencontrerez en utilisation normale, y compris les opcodes non valides , sont traités en interceptant et en récupérant d'une manière ou en ignorant simplement l'erreur et en continuant l'exécution dans un état potentiellement non propre, en ayant éventuellement défini un indicateur d'erreur.
un CVn
8
Si vous ne capturez pas la division par zéro, le résultat serait, dans le jargon de la programmation, "Comportement indéfini". Cela signifie que l'ordinateur peut faire n'importe quoi. Comme le mentionne Bergi, il est possible qu’il passe une boucle en buggy et s’accroche. Il peut simplement produire une série de bits non spécifiée qui est venue de la mise en oeuvre de la logique de division (rappelez-vous, un ordinateur ne "divise" pas au sens mathématique. Il effectue une opération sur deux nombres, ce qui est assez proche de la division nous appelons généralement cela simplement "division" ... voir aussi arrondi en virgule flottante).
Cort Ammon
34

Cela dépend de la langue, du compilateur, de l'utilisation d'entiers ou de nombres à virgule flottante, etc.

Pour les nombres à virgule flottante, la plupart des implémentations utilisent la norme IEEE 754 , dans laquelle la division par 0 est bien définie. 0/0 donne un résultat bien défini de NaN (pas un nombre), et x / 0 pour x 0 donne soit + Infinity soit -Infinity, en fonction du signe de x.

Dans des langages tels que C, C ++, etc., la division par zéro appelle un comportement indéfini. Donc, selon la définition du langage, tout peut arriver. Surtout des choses que vous ne voulez pas arriver. Comme si tout fonctionnait parfaitement bien lorsque vous écrivez le code et détruisez les données lorsque votre client les utilise. Donc, du point de vue de la langue, ne faites pas cela . Certaines langues garantissent le blocage de votre application. c'est à eux de décider comment cela est mis en œuvre. Pour ces langues, la division par zéro va planter.

De nombreux processeurs ont une sorte d'instruction "diviser" intégrée, qui se comportera différemment selon le processeur. Sur les processeurs Intel 32 bits et 64 bits, les instructions "diviser" planteront votre application lorsque vous essayez de diviser par zéro. D'autres processeurs peuvent se comporter différemment.

Si un compilateur détecte qu'une division par zéro va se produire lorsque vous exécutez du code et qu'il est gentil avec ses utilisateurs, il vous avertira probablement et générera une instruction intégrée "divide" afin que le comportement soit le même. même.

gnasher729
la source
22
"Sur les processeurs Intel 32 bits et 64 bits, les instructions de" division "planteront votre application lorsque vous essayez de diviser par zéro." Citation requise. Les processeurs n'ont aucune idée des applications, ils exécutent des instructions et (si nous incluons la MMU) imposent des limites d'accès mémoire (sauf dans l' anneau 0 ou équivalent dans des architectures non Intel-x86). Le fait que l'instruction fasse partie de l'application A plutôt que de l'application B ou du composant du système d'exploitation C n'a aucune incidence sur la CPU; si l'instruction peut être l'instruction X ou utiliser l'adresse mémoire Y est pertinent.
un CVn
1
Pour ajouter au commentaire de @ MichaelKjörling: Le système d'exploitation a des façons de ne pas noter l'application de ce problème (et d'autres types d'erreur). Dans le monde de Windows , il est la EXCEPTION_INT_DIVIDE_BY_ZEROvaleur de la EXCEPTION_RECORDqui sera gérée par le (je l' espère) installé CONSTRUIT Exception Handling Handler
user45891
1
Parfois, ils font des choses autres que de garantir le blocage de votre application. Par exemple, de nombreuses langues / plates-formes garantissent qu’elles lèveront une exception avec division par zéro. Vous pouvez alors attraper et gérer ladite exception sans planter.
Reirab
2
Vous pouvez supprimer le "peut" dans "D'autres processeurs peuvent se comporter différemment": sur la plate-forme PowerPC, la division produit simplement un résultat égal à zéro lors de la division par zéro. Ce qui est beaucoup plus utile que le comportement de panique de la plate-forme X86.
cmaster
13

On dirait que vous vous demandez ce qui se passerait si quelqu'un fabriquait un processeur qui ne vérifiait pas explicitement la valeur zéro avant la division. Ce qui arriverait dépend entièrement de la mise en œuvre de la division. Sans entrer dans les détails, un type de mise en oeuvre produirait un résultat avec tous les bits définis, par exemple 65535 sur un processeur 16 bits. Un autre pourrait raccrocher.

Bingo
la source
1

Mais ce que je me demandais, c’est si l’ordinateur tente même de diviser par zéro ou s’il a simplement une "protection intégrée", de sorte que, quand il "voit" 0/0, il retourne une erreur avant même de tenter de la calculer.

Étant donné que x/0cela n’a aucun sens, les ordinateurs doivent toujours vérifier la division par zéro. Il y a un problème ici: les programmeurs veulent calculer (a+b)/csans avoir à vérifier si ce calcul est logique. La réponse sous-jacente à la division par zéro par le CPU + le type de numéro + le système d'exploitation + le langage consiste à faire quelque chose d'assez grave (par exemple, bloquer le programme) ou à faire quelque chose de trop anodin sens tel que le point flottant IEEE NaN, un nombre qui n’est pas un nombre).

Dans un contexte ordinaire, un programmeur doit savoir si (a+b)/ccela a du sens. Dans ce contexte, il n'y a aucune raison de vérifier la division par zéro. Si la division par zéro se produit, et si le langage machine + le langage d'implémentation + le type de données + le système d'exploitation répondent à cela pour faire planter le programme, c'est bien. Si la réponse est de créer une valeur qui pourrait éventuellement polluer chaque numéro du programme, ce n'est pas grave.

Dans le monde de l'informatique à haute fiabilité, ni "drastique" ni "trop ​​bénigne" ne constitue la meilleure chose à faire. Ces réponses par défaut peuvent tuer un patient, écraser un avion de ligne ou faire exploser une bombe au mauvais endroit. Dans un environnement de haute fiabilité, un programmeur qui écrit (a+b)/cest sélectionné à mort lors de la révision du code ou, à notre époque, peut-être automatiquement à mort par un outil vérifiant les constructions verboten. Dans cet environnement, ce programmeur devrait plutôt avoir écrit quelque chose dans le sens de div(add(a,b),c)(et éventuellement une vérification du statut d'erreur). Sous le capot, les fonctions / macros div(ainsi que les add) protègent contre une division par zéro (ou un débordement dans le cas de add). Ce que cette protection implique est très spécifique à la mise en œuvre.

David Hammen
la source
Ce n'est pas parce que NaN n'obéit pas à l'arithmétique que vous avez apprise à l'école que cela n'a aucun sens. Il obéit à une arithmétique différente
Caleth
-2

Nous savons maintenant que x/0et 0/0n'ont pas de réponses bien définies. Qu'advient-il si vous essayez de calculer 0/0quand même?

Sur un système moderne, le calcul est transmis à la MPU au sein de la CPU et est signalé comme une opération non conforme NaN.

Sur un système beaucoup plus ancien, tel que les ordinateurs personnels des années 80 ne disposant pas de division sur puce, le calcul était effectué avec le logiciel utilisé. Il y a quelques choix possibles:

  • Soustrayez des copies de plus en plus petites du diviseur jusqu'à ce que la valeur atteigne zéro et gardez une trace des copies dimensionnées qui ont été soustraites.
    • S'il vérifie zéro avant la première soustraction, il se fermera rapidement et le résultat sera 0
    • S'il suppose qu'il doit pouvoir soustraire au moins une fois, le résultat sera 1
  • Calculez les logarithmes des deux nombres, soustrayez-les et augmentez e à la puissance du résultat. Une méthode très inefficace comparée à la méthode de soustraction ci-dessus, mais mathématiquement valide
    • Un débordement peut survenir lors de la tentative de calcul log(0)et le logiciel utiliserait ses routines de traitement des erreurs ou se bloquerait
    • Le logiciel peut supposer que tous les logarithmes peuvent être calculés en un nombre d'étapes fixe et renvoyer une valeur importante mais incorrecte. Puisque les deux logarithmes seraient identiques, la différence serait 0et e 0 = 1, donnant un résultat de1

En d'autres termes, ce qui se produirait dépendrait de la mise en œuvre et il serait possible d'écrire un logiciel qui produirait des résultats corrects et prévisibles pour chaque valeur, mais des valeurs apparemment étranges resteraient 0/0néanmoins cohérentes en interne.

CJ Dennis
la source
3
Cette question concerne la division par zéro dans les nombres entiers, et il n’existe rien de tel que NaNdans les nombres entiers.
David Hammen
3
Aucun processeur ne va calculer les journaux et soustraire pour calculer le résultat de la division. Le temps d'instruction du logarithme est supérieur de plusieurs ordres de grandeur à une division. Quelle est la valeur de log (0)?
wallyk
1
@DavidHammen Le PO n'a jamais mentionné les entiers, pas plus que quiconque ayant commenté la question. Les entiers ne sont mentionnés que dans les réponses.
CJ Dennis
@wallyk J'ai déjà dit dans ma réponse que ces logarithmes sont very inefficientpour la division. Le coût pour l'arithmétique est (addition = soustraction) <= multiplication <= division. Si vous n'avez pas de MPU capable de diviser dans le même nombre de cycles d'horloge que l'addition (généralement un), la division est plus onéreuse que l'addition et la soustraction et généralement plus chère que la multiplication.
CJ Dennis