Comment gérer la division par zéro dans une langue qui ne prend pas en charge les exceptions?

62

Je suis en train de développer un nouveau langage de programmation pour répondre à certains besoins de l'entreprise. Ce langage est destiné aux utilisateurs novices. Donc, il n'y a pas de support pour la gestion des exceptions dans la langue, et je ne m'attendrais pas à ce qu'ils l'utilisent même si je l'ajoutais.

J'ai atteint le point où je dois implémenter l'opérateur de division et je me demande comment gérer au mieux une erreur de division par zéro?

Il me semble n'avoir que trois façons possibles de traiter cette affaire.

  1. Ignorer l'erreur et produire 0le résultat. Enregistrer un avertissement si possible.
  2. Ajouter NaNcomme valeur possible pour les nombres, mais cela soulève des questions sur la façon de gérer les NaNvaleurs dans d'autres domaines de la langue.
  3. Terminez l'exécution du programme et signalez à l'utilisateur qu'une erreur grave s'est produite.

L'option n ° 1 semble la seule solution raisonnable. L'option n ° 3 n'est pas pratique car ce langage sera utilisé pour exécuter la logique comme un cron nocturne.

Quelles sont mes alternatives pour gérer une erreur de division par zéro, et quels sont les risques associés à l'option # 1.

Réactionnel
la source
12
si vous aviez ajouté un support d'exception et que l'utilisateur ne l'avait pas compris, vous auriez l'option # 3
fratchet freak
82
Je suis curieux de savoir quelle exigence stupide vous obligerait à créer un tout nouveau langage de programmation. Dans mon expérience, chaque langue jamais créé suce (dans la conception ou l' exécution, souvent les deux) et il a fallu des efforts déraisonnablement beaucoup à même obtenir que beaucoup. Il y a quelques exceptions au premier, mais pas au second, et comme elles représentent facilement moins de 0,01% des cas, il s'agit probablement d'erreurs de mesure ;-)
16
@delnan la plupart des nouvelles langues sont créées pour permettre aux règles métier d'être dissociées de la manière dont elles sont implémentées. L'utilisateur n'a pas besoin de savoir comment a reject "Foo"été mis en œuvre, mais simplement qu'il rejette un document s'il contient le mot clé Foo. J'essaie de rendre le langage aussi facile à lire en utilisant des termes familiers. Donner à un utilisateur son propre langage de programmation lui permet d'ajouter des règles métier sans dépendre du personnel technique.
Reactgular
19
@ Mathew Foscarini. Ne jamais, jamais, ignorer l'erreur et renvoyer silencieusement 0. Lors d'une division, 0 peut être une valeur parfaitement légale (pour une raison quelconque, il existe une telle chose dans Power Basic et c'est vraiment pénible). Si vous divisez des nombres en virgule flottante, Nan ou Inf serait bien (regardez dans IEEE 754 pour comprendre pourquoi). Si vous divisez des entiers, vous pouvez arrêter le programme, une division par 0 ne devrait jamais être autorisée (à moins que vous ne souhaitiez implémenter un système d'exception véritable).
16
Je me suis amusé et fasciné par un domaine métier suffisamment complexe pour justifier un langage de programmation propriétaire, complet, mais suffisamment souple pour tolérer des résultats extrêmement erronés.
Mark E. Haase

Réponses:

98

Je déconseillerais fortement la position n ° 1, car ignorer les erreurs est un anti-motif dangereux. Cela peut conduire à des bugs difficiles à analyser. Définir le résultat d’une division par zéro à 0 n’a aucun sens, et la poursuite de l’exécution du programme avec une valeur insensée va poser problème. Surtout quand le programme fonctionne sans surveillance. Lorsque l'interprète de programme s'aperçoit qu'il y a une erreur dans le programme (et qu'une division par zéro est presque toujours une erreur de conception), il est préférable de l'abandonner et de tout conserver tel quel, plutôt que de remplir votre base de données de manière erronée.

En outre, il est peu probable que vous réussissiez à suivre à la lettre ce modèle. Tôt ou tard, vous rencontrerez des situations d'erreur qui ne peuvent pas être ignorées (par exemple, manque de mémoire ou débordement de pile) et vous devrez quand même implémenter un moyen de terminer le programme.

L'option n ° 2 (utiliser NaN) consisterait en un peu de travail, mais pas autant que vous ne le pensez. La manière de gérer NaN dans différents calculs est bien documentée dans la norme IEEE 754; vous pouvez donc faire exactement ce que fait la langue dans laquelle votre interprète est écrit.

Au fait: Nous essayons de créer un langage de programmation utilisable par des non-programmeurs depuis 1964 (Dartmouth BASIC). Jusqu'ici, nous avons échoué. Mais bonne chance quand même.

Philipp
la source
14
+1 merci. Vous m'avez convaincu de commettre une erreur, et maintenant que j'ai lu votre réponse, je ne comprends pas pourquoi j'ai hésité. PHPa été une mauvaise influence sur moi.
Reactgular
24
Oui, il a. Lorsque j'ai lu votre question, j'ai tout de suite pensé qu'il était très difficile, en PHP, de produire des résultats incorrects et de continuer à transporter des camions malgré les erreurs. Il y a de bonnes raisons pour que PHP soit une exception.
Joel
4
+1 pour le commentaire BASIC. Je ne conseille pas d'utiliser NaNdans la langue d'un débutant, mais en général, bonne réponse.
Ross Patterson
8
@Joel S'il avait vécu assez longtemps, Dijkstra aurait probablement déclaré: "L'utilisation de [PHP] paralyse l'esprit, son enseignement doit donc être considéré comme un délit pénal."
Ross Patterson
12
@ Ross. "l'arrogance en informatique se mesure en nano-Dijkstras" - Alan Kay
33

1 - Ignorer l'erreur et produire 0le résultat. Enregistrer un avertissement si possible.

Ce n'est pas une bonne idée. Du tout. Les gens vont commencer à en dépendre et, si vous le corrigez un jour, vous casserez beaucoup de code.

2 - Ajouter NaNcomme valeur possible pour les nombres, mais cela soulève des questions sur la façon de gérer les NaNvaleurs dans d'autres domaines de la langue.

Vous devez manipuler NaN comme les runtimes d’autres langues le font: Tout calcul ultérieur donne également NaN et chaque comparaison (même NaN == NaN) donne faux.

Je pense que cela est acceptable, mais pas nécessairement nouveau venu.

3 - Terminez l'exécution du programme et signalez à l'utilisateur qu'une erreur grave s'est produite.

C’est la meilleure solution à mon avis. Avec cette information en main, les utilisateurs devraient être capables de gérer le 0. Vous devez fournir un environnement de test, en particulier s’il est prévu de fonctionner une fois par nuit.

Il y a aussi une quatrième option. Faites de la division une opération ternaire. N'importe lequel de ces deux fonctionnera:

  • div (numérateur, dénumérateur, alternative_result)
  • div (numerator, denumerator, alternative_denumerator)
back2dos
la source
Mais si vous faites NaN == NaNêtre false, alors vous devrez ajouter une isNaN()fonction afin que les utilisateurs sont en mesure de détecter NaNs.
AJMansfield
2
@AJMansfield: Soit ça, ou les mettre en œuvre eux-mêmes: isNan(x) => x != x. Néanmoins, lorsque NaNvotre code de programmation apparaît, vous ne devez pas commencer à ajouter des isNaNvérifications, mais plutôt rechercher la cause et y effectuer les vérifications nécessaires. Il est donc important NaNde propager pleinement.
back2dos
5
NaNs sont principalement contre-intuitifs. Dans la langue d'un débutant, ils sont morts à l'arrivée.
Ross Patterson
2
@ RossPatterson Mais un débutant peut facilement dire 1/0: vous devez faire quelque chose avec. Il n'y a pas de résultat éventuellement utile autre que Infou NaN- quelque chose qui propagera l'erreur plus loin dans le programme. Sinon, la seule solution consiste à arrêter avec une erreur à ce stade.
Mark Hurd
1
L’option 4 pourrait être améliorée en permettant l’invocation d’une fonction, qui pourrait à son tour effectuer l’action nécessaire pour récupérer le diviseur 0 inattendu.
CyberFonic
21

Arrêtez l'application en cours avec un parti pris extrême. (Tout en fournissant des informations de débogage adéquates)

Ensuite, éduquez vos utilisateurs pour qu'ils identifient et gèrent les conditions dans lesquelles le diviseur peut être nul (valeurs entrées par l'utilisateur, etc.).

Dave Nay
la source
13

Dans Haskell (et similaire à Scala), au lieu de jeter des exceptions (ou le retour des références null) les types d'enveloppe Maybeet Eitherpeuvent être utilisés. Avec Maybel'utilisateur a une chance de tester si la valeur qu'il a obtenue est "vide", ou il pourrait fournir une valeur par défaut lors du "déroulement". Eitherest similaire, mais peut être utilisé retourne un objet (une chaîne d'erreur, par exemple) décrivant le problème s'il en existe un.

Landei
la source
1
C'est vrai, mais notez que Haskell ne l'utilise pas pour la division par zéro. Au lieu de cela, chaque type Haskell a implicitement une valeur possible "bottom". Ce n'est pas comme des pointeurs nuls dans le sens où c'est la "valeur" d'une expression qui ne se termine pas. Bien sûr, vous ne pouvez pas tester la non-fin en tant que valeur, mais en sémantique opérationnelle, les cas qui ne se terminent pas font partie du sens d'une expression. Dans Haskell, cette valeur "inférieure" gère également d'autres résultats de cas d'erreur tels que la error "some message"fonction en cours d'évaluation.
Steve314
Personnellement, si l'effet d'abandonner l'ensemble du programme est considéré comme valide, j'ignore pourquoi le code pur ne peut pas avoir pour effet de générer une exception, mais c'est juste pour moi - Haskellne permet pas aux expressions pures de renvoyer des exceptions.
Steve314
Je pense que c'est une bonne idée car, à l'exception d'une exception, toutes les options proposées ne communiquent pas aux utilisateurs qu'ils ont commis une erreur. L'idée de base est que l'utilisateur commet une erreur avec la valeur qu'il a attribuée au programme. Le programme doit donc l'informer qu'il a mal saisi l'entrée (l'utilisateur peut alors penser à un moyen de remédier à la situation). Sans dire aux utilisateurs leur erreur, toute solution est si étrange.
InformedA
Je pense que c'est la voie à suivre ... Le langage de programmation Rust l'utilise abondamment dans sa bibliothèque standard.
aochagavia
12

D'autres réponses ont déjà examiné les mérites relatifs de vos idées. J'en propose une autre: utiliser une analyse de flux de base pour déterminer si une variable peut être égale à zéro. Ensuite, vous pouvez simplement interdire la division par des variables potentiellement nulles.

x = ...
y = ...

if y ≠ 0:
  return x / y    // In this block, y is known to be nonzero.
else:
  return x / y    // This, however, is a compile-time error.

Sinon, utilisez une fonction d'assertion intelligente qui établit des invariants:

x = ...
require x ≠ 0, "Unexpected zero in calculation"
// For the remainder of this scope, x is known to be nonzero.

Cela équivaut à renvoyer une erreur d'exécution (vous contournez entièrement des opérations non définies), mais présente l'avantage que le chemin du code n'a même pas besoin d'être touché pour que la défaillance potentielle soit exposée. Cela peut se faire un peu comme une vérification de type ordinaire, en évaluant toutes les branches d'un programme avec des environnements de frappe imbriqués pour suivre et vérifier les invariants:

x = ...           // env1 = { x :: int }
y = ...           // env2 = env1 + { y :: int }
if y ≠ 0:         // env3 = env2 + { y ≠ 0 }
  return x / y    // (/) :: (int, int ≠ 0) → int
else:             // env4 = env2 + { y = 0 }
  ...
...               // env5 = env2

En outre, il s’étend naturellement à la portée et à la nullvérification, si votre langue possède de telles fonctionnalités.

Jon Purdy
la source
4
Idée géniale, mais ce type de résolution de contraintes est NP-complet. Imaginez quelque chose comme def foo(a,b): return a / ord(sha1(b)[0]). L'analyseur statique ne peut pas inverser SHA-1. Clang a ce type d'analyse statique et son excellent pour la recherche de bugs peu profonds, mais il y a beaucoup de cas qu'il ne peut pas gérer.
Mark E. Haase
9
ce n'est pas NP-complet, c'est impossible - dit arrêter le lemme. Cependant, l'analyseur statique n'a pas besoin de résoudre ce problème, il peut simplement mettre un terme à une telle déclaration et vous obliger à ajouter une assertion ou une décoration explicite.
MK01
1
@ MK01: En d'autres termes, l'analyse est «conservatrice».
Jon Purdy
11

Le numéro 1 (insérer undebuggable zero) est toujours mauvais. Le choix entre # 2 (propager NaN) et # 3 (tuer le processus) dépend du contexte et devrait idéalement être un paramètre global, comme dans Numpy.

Si vous effectuez un grand calcul intégré, propager NaN est une mauvaise idée car il finira par se propager et infecter l'ensemble de votre calcul - lorsque vous regardez les résultats le matin et constatez qu'ils sont tous NaN, vous ' Je dois jeter les résultats et recommencer quand même. Il aurait été préférable que le programme se termine, que vous receviez un appel au milieu de la nuit et que vous le répariez - en termes de nombre d'heures perdues, au moins.

Si vous faites beaucoup de petits calculs, pour la plupart indépendants (comme des calculs parallèles avec réduction de la carte ou parallèlement embarrassants) et que vous pouvez tolérer qu'un pourcentage d'entre eux soit inutilisable en raison de NaN, c'est probablement la meilleure option. Terminer le programme et ne pas faire les 99% qui seraient bons et utiles en raison du 1% qui sont mal formés et se divisent par zéro pourrait être une erreur.

Une autre option, liée aux NaN: la même spécification à virgule flottante IEEE définit Inf et -Inf, et celles-ci sont propagées différemment de NaN. Par exemple, je suis à peu près sûr que Inf> tout nombre et -Inf <tout nombre, ce qui serait ce que vous vouliez si votre division par zéro se produisait, car le zéro était supposé être un petit nombre. Si vos entrées sont arrondies et souffrent d’erreurs de mesure (comme des mesures physiques à la main), la différence entre deux grandes quantités peut avoir pour résultat zéro. Sans la division par zéro, vous auriez obtenu un nombre élevé, et peut-être ne vous souciez-vous pas de sa taille. Dans ce cas, In et -Inf sont des résultats parfaitement valides.

Cela peut être formellement correct aussi - dites simplement que vous travaillez dans les réels étendus.

Jim Pivarski
la source
Mais nous ne pouvons pas dire si le dénominateur était censé être positif ou négatif, de sorte que la division pourrait donner + inf lorsque l'on désirait -inf, ou inversement.
Daniel Lubarov
En réalité, votre erreur de mesure est trop petite pour faire la distinction entre + inf et -inf. Cela ressemble beaucoup à la sphère de Riemann, dans laquelle tout le plan complexe est tracé en une boule avec exactement un point infini (le point diamétralement opposé à l'origine). De très grands nombres positifs, de très grands nombres négatifs et même de très grands nombres imaginaires et complexes sont tous proches de ce point infini. Avec une petite erreur de mesure, vous ne pouvez pas les distinguer.
Jim Pivarski
Si vous travaillez dans ce type de système, vous devez identifier + inf et -inf comme équivalents, tout comme vous devez identifier les équivalents +0 et -0, bien qu'ils aient des représentations binaires différentes.
Jim Pivarski
8

3. Terminez l'exécution du programme et signalez à l'utilisateur qu'une erreur grave s'est produite.

[Cette option] n'est pas pratique…

Bien sûr, c’est pratique: c’est la responsabilité des programmeurs d’écrire un programme qui a du sens. Diviser par 0 n'a aucun sens. Par conséquent, si le programmeur effectue une division, il lui incombe également de vérifier au préalable que le diviseur n'est pas égal à 0. Si le programmeur n'effectue pas cette vérification de validation, il doit alors se rendre compte de cette erreur dès que possibles, et les résultats de calculs dénormalisés (NaN) ou incorrects (0) ne seront d'aucun secours à cet égard.

L’option 3 se trouve être celle que je vous aurais recommandée, d’ailleurs, pour être la plus simple, la plus honnête et la plus mathématiquement correcte.

Stakx
la source
4

Cela me semble une mauvaise idée d’exécuter des tâches importantes ("Nightly Cron") dans un environnement où les erreurs sont ignorées. C'est une idée terrible d'en faire une fonctionnalité. Ceci exclut les options 1 et 2.

L'option 3 est la seule solution acceptable. Les exceptions ne doivent pas nécessairement faire partie du langage, mais font partie de la réalité. Votre message de résiliation doit être aussi spécifique et informatif que possible concernant l’erreur.

Ddyer
la source
3

IEEE 754 a en fait une solution bien définie pour votre problème. Gestion des exceptions sans utiliser exceptions http://en.wikipedia.org/wiki/IEEE_floating_point#Exception_handling

1/0  = Inf
-1/0 = -Inf
0/0  = NaN

De cette façon, toutes vos opérations ont un sens mathématique.

\ lim_ {x \ to 0} 1 / x = Inf

À mon avis, suivre IEEE 754 est tout à fait logique car cela garantit que vos calculs sont aussi corrects que sur un ordinateur et que vous êtes également cohérent avec le comportement des autres langages de programmation.

Le seul problème qui se pose est que Inf et NaN vont contaminer vos résultats et vos utilisateurs ne sauront pas exactement d'où vient le problème. Regardez une langue comme Julia qui le fait très bien.

julia> 1/0
Inf

julia> -1/0
-Inf

julia> 0/0
NaN

julia> a = [1,1,1] ./ [2,1,0]
3-element Array{Float64,1}:
   0.5
   1.0
 Inf

julia> sum(a)
Inf

julia> a = [1,1,0] ./ [2,1,0]
3-element Array{Float64,1}:
   0.5
   1.0
 NaN

julia> sum(a)
NaN

L'erreur de division est propagée correctement par les opérations mathématiques, mais l'utilisateur ne sait pas nécessairement de quelle opération provient l'erreur.

edit:Je n'ai pas vu la deuxième partie de la réponse de Jim Pivarski qui est essentiellement ce que je dis ci-dessus. Ma faute.

Wallnuss
la source
2

SQL, facilement le langage le plus utilisé par les non-programmeurs, est le n ° 3, quelle que soit la valeur de celui-ci. Dans mon expérience d’observation et d’aide auprès des non-programmeurs qui écrivent du SQL, ce comportement est généralement bien compris et facilement compensé (par une instruction case ou similaire). Le message d'erreur que vous obtenez a tendance à être assez direct, par exemple, dans Postgres 9, vous obtenez "ERREUR: division by zero".

Noah Yetter
la source
2

Je pense que le problème est "ciblé sur les utilisateurs novices. -> Donc, il n'y a pas de soutien pour ..."

Pourquoi pensez-vous que la gestion des exceptions est problématique pour les utilisateurs novices?

Quel est le pire? Vous avez une fonction "difficile" ou vous ne savez pas pourquoi quelque chose est arrivé? Que pourrait confondre plus? Un crash avec un core dump ou "Erreur fatale: Diviser par zéro"?

Au lieu de cela, je pense qu’il est préférable de viser de très bonnes erreurs de message. Donc, faites plutôt: "Mauvais calcul, Divisez 0/0" (c.-à-d.: Affichez toujours les DONNÉES qui causent le problème, pas seulement le type de problème). Regardez comment PostgreSql fait les erreurs de message, qui sont géniales à mon humble avis.

Cependant, vous pouvez rechercher d'autres moyens de travailler avec des exceptions telles que:

http://dlang.org/exception-safe.html

J'ai aussi rêvé de construire un langage, et dans ce cas, je pense que combiner un événement Maybe / Optionnel avec des exceptions normales pourrait être le meilleur:

def openFile(fileName): File | Exception
    if not(File.Exist(fileName)):
        raise FileNotExist(fileName)
    else:
        return File.Open()

#This cause a exception:

theFile = openFile('not exist')

# But this, not:

theFile | err = openFile('not exist')
Mamcx
la source
1

À mon avis, votre langage devrait fournir un mécanisme générique de détection et de traitement des erreurs. Les erreurs de programmation doivent être détectées au moment de la compilation (ou le plus tôt possible) et doivent normalement mener à la fin du programme. Les erreurs résultant de données inattendues ou erronées, ou de conditions externes imprévues, doivent être détectées et mises à disposition pour une action appropriée, tout en permettant au programme de continuer autant que possible.

Les actions plausibles incluent (a) terminer (b) demander à l'utilisateur une action (c) consigner l'erreur (d) remplacer une valeur corrigée (e) définir un indicateur à tester dans le code (f) invoquer une routine de traitement d'erreur. Lesquels de ces choix sont disponibles et par quels moyens vous devez faire des choix.

D'après mon expérience, les erreurs de données courantes telles que les conversions défectueuses, la division par zéro, le dépassement de capacité et les valeurs hors limites sont bénignes et doivent par défaut être gérées en substituant une valeur différente et en définissant un indicateur d'erreur. Le (non-programmeur) utilisant ce langage verra les données erronées et comprendra rapidement la nécessité de vérifier les erreurs et de les traiter.

[Pour un exemple, considérons une feuille de calcul Excel. Excel ne met pas fin à votre feuille de calcul à cause d’un nombre excessif ou autre. La cellule reçoit une valeur étrange et vous allez découvrir pourquoi et la réparer.]

Donc, pour répondre à votre question: vous ne devriez certainement pas terminer. Vous pouvez substituer NaN mais vous ne devriez pas rendre cela visible, assurez-vous simplement que le calcul est terminé et génère une valeur élevée étrange. Et définissez un indicateur d'erreur afin que les utilisateurs qui en ont besoin puissent déterminer qu'une erreur s'est produite.

Divulgation: J'ai créé une telle implémentation de langage (Powerflex) et abordé exactement ce problème (et bien d'autres) dans les années 1980. Il n’ya eu que peu ou pas de progrès sur les langues pour les non-programmeurs au cours des 20 dernières années environ, et vous attirerez des tas de critiques pour essayer, mais j’espère vraiment que vous réussirez.

david.pfx
la source
1

J'ai aimé l'opérateur ternaire où vous fournissez une valeur alternative au cas où le dénominateur est 0.

Une autre idée que je n'ai pas vue est de produire une valeur "invalide" générale. Un général "cette variable n'a pas de valeur parce que le programme a fait quelque chose de mal", qui porte une trace de pile complète avec lui-même. Ensuite, si vous utilisez cette valeur n'importe où, le résultat est à nouveau invalide, avec la nouvelle opération tentée en premier (c'est-à-dire que si la valeur non valide apparaît dans une expression, l'expression entière devient invalide et aucun appel de fonction n'est tenté; une exception serait Opérateurs être booléens - vrai ou invalide est vrai et faux et invalide est faux - il peut y avoir d'autres exceptions à cela aussi. Une fois que cette valeur n'est plus référencée nulle part, vous enregistrez une longue et belle description de la chaîne entière dans laquelle les choses ne vont pas et vous continuez comme si de rien n'était. Peut-être envoyer la trace par courrier électronique au responsable du projet ou quelque chose du genre.

Quelque chose comme la monade peut-être fondamentalement. Cela fonctionnera aussi avec tout ce qui peut échouer et vous pouvez permettre aux gens de construire leurs propres invalides. Et le programme continuera à fonctionner tant que l'erreur ne sera pas trop profonde, ce qui est vraiment recherché ici, à mon avis.

Moshev
la source
1

Une division par zéro a deux raisons fondamentales.

  1. Dans un modèle précis (comme les entiers), vous obtenez une division par zéro DBZ car l'entrée est incorrecte. C’est le genre de DBZ auquel la plupart d’entre nous pensons.
  2. Dans un modèle non précis (comme un pt flottant), vous pouvez obtenir une zone DBZ en raison d'une erreur d'arrondi, même si la saisie est valide. C’est ce à quoi nous ne pensons pas normalement.

Pour 1. vous devez informer les utilisateurs qu'ils ont commis une erreur, car ce sont eux qui en sont responsables et qui savent le mieux comment remédier à la situation.

Pour 2. Ce n'est pas la faute de l'utilisateur, vous pouvez pointer du doigt un algorithme, une implémentation matérielle, etc. Une solution raisonnable consiste donc à poursuivre les opérations de manière raisonnable.

Je peux voir que la personne qui pose cette question a demandé le cas 1. Vous devez donc communiquer avec l'utilisateur. En utilisant n'importe quel standard de virgule flottante, Inf, -Inf, Nan, IEEE ne convient pas à cette situation. Stratégie fondamentalement fausse.

InforméA
la source
0

Interdit dans la langue. C’est-à-dire qu’il est interdit d’autoriser la division par un nombre jusqu’à ce qu’il soit prouvé que ce n’est pas zéro, généralement en le testant d’abord. C'est à dire.

int div = random(0,100);
int b = 10000 / div; // Error E0000: div might be zero
MSalters
la source
Pour ce faire, vous avez besoin d'un nouveau type numérique, un nombre naturel, par opposition à un entier. Cela pourrait être ... difficile ... à gérer.
Servy
@ Service: Non, vous ne voudriez pas. Pourquoi voudrais-tu? Vous avez besoin d’une logique dans le compilateur pour déterminer les valeurs possibles, mais vous le voulez quand même (pour des raisons d’optimisation).
MSalters
Si vous n'avez pas un type différent, un pour zéro et un pour des valeurs non nulles, vous ne pourrez pas résoudre le problème dans le cas général. Vous pouvez soit avoir des faux positifs, et forcer l'utilisateur à vérifier la valeur zéro plus souvent qu'il ne le devrait, ou vous allez créer des situations dans lesquelles il est toujours possible de diviser par zéro.
Servy
@Servy: Vous vous trompez: un compilateur peut suivre cet état sans avoir besoin d'un tel type, et par exemple, GCC le fait déjà. Par exemple, le type C intautorise les valeurs zéro, mais GCC peut toujours déterminer où, dans le code, les intes spécifiques ne peuvent pas être zéro.
MSalters
2
Mais seulement dans certains cas; il ne peut pas le faire, avec une précision de 100%, dans tous les cas. Vous aurez soit des faux positifs ou des faux négatifs. C'est vraisemblablement vrai. Par exemple, je pourrais créer un extrait de code qui pourrait même ne pas être complet . Si le compilateur ne sait même pas s’il a terminé, comment pourrait-il savoir si l’entier résultant est différent de zéro? Il peut attraper de simples cas évidents, mais pas tous .
Servy
0

Lorsque vous écrivez un langage de programmation, vous devez en tirer parti et rendre obligatoire l’inclusion d’une action pour le schéma par zéro. a <= n / c: 0 div-by-zero-action

Je sais que ce que je viens de suggérer consiste essentiellement à ajouter un "goto" à votre PL.

Stephen
la source