44 votes

Incohérence du comportement de la division par zéro entre différents types de valeurs

Veuillez considérer le code et les commentaires suivants :

Console.WriteLine(1 / 0); // will not compile, error: Division by constant zero

int i = 0;
Console.WriteLine(1 / i); // compiles, runs, throws: DivideByZeroException

double d = 0;
Console.WriteLine(1 / d); // compiles, runs, results in: Infinity   

Je peux comprendre que le compilateur vérifie activement la constante de division par zéro et l'exception DivideByZeroException au moment de l'exécution, mais.. :

Pourquoi l'utilisation d'un double dans une division par zéro renvoie-t-elle Infinity plutôt que de lever une exception ? S'agit-il d'une erreur de conception ou d'un bogue ?

Juste pour le plaisir, j'ai fait la même chose en VB.NET, avec des résultats "plus cohérents" :

dim d as double = 0.0
Console.WriteLine(1 / d) ' compiles, runs, results in: Infinity

dim i as Integer = 0
Console.WriteLine(1 / i) '  compiles, runs, results in: Infinity

Console.WriteLine(1 / 0) ' compiles, runs, results in: Infinity

EDITAR:

En me basant sur les commentaires de kekekela, j'ai effectué le test suivant qui a donné un résultat infini :

Console.WriteLine(1 / .0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001);

Ce test semble corroborer l'idée et un double littéral de 0.0 est en fait une très, très infime fraction qui aboutira à l'infini...

4 votes

Voici mon article sur le sujet : blogs.msdn.com/b/ericlippert/archive/2009/10/15/

37voto

Dan Tao Points 60518

En bref : le double définit une valeur pour l'infini tandis que le type int le type ne le fait pas. Ainsi, dans le double le résultat du calcul est une valeur que vous pouvez effectivement exprimer dans le type donné puisqu'il est défini. Dans le int Dans ce cas, il n'y a pas de valeur pour l'infini et donc aucun moyen de renvoyer un résultat précis. D'où l'exception.

VB.NET fait les choses un peu différemment ; la division d'un nombre entier donne automatiquement une valeur en virgule flottante en utilisant la fonction / opérateur. Ceci afin de permettre aux développeurs d'écrire, par exemple, l'expression 1 / 2 et le faire évaluer par 0.5 ce que certains considèrent comme intuitif. Si vous voulez voir un comportement cohérent avec le C#, essayez ceci :

Console.WriteLine(1 \ 0)

Notez l'utilisation du division de nombres entiers opérateur ( \ pas / ) ci-dessus. Je pense que vous obtiendrez une exception (ou une erreur de compilation - je ne sais pas laquelle).

De même, essayez ceci :

Dim x As Object = 1 / 0
Console.WriteLine(x.GetType())

Le code ci-dessus donnera comme résultat System.Double .

Quant à la question de l'imprécision, voici une autre façon de voir les choses. Ce n'est pas que le double n'a pas de valeur pour exactement zéro (il en a une) ; au contraire, le type double n'est pas destiné à fournir des résultats mathématiquement exacts en premier lieu. (Certaines valeurs peuvent être représentées exactement, oui. Mais calculs ne donnent aucune promesse d'exactitude). Après tout, la valeur de la mathématiques expression 1 / 0 n'est pas défini (la dernière fois que j'ai vérifié). Mais 1 / x s'approche de l'infini lorsque x s'approche de zéro. Donc, de ce point de vue, si nous ne pouvons pas représenter la plupart des fractions n / m exactement de toute façon, il est logique de traiter le x / 0 comme approximatif et donner la valeur qu'il approches --Encore une fois, l'infini est défini, au moins.

2 votes

Bien que très utilisable, cette réponse est également légèrement fausse. La réponse est fausse car la division par zéro n'est pas l'infini - elle est mathématiquement indéfinie. La vraie réponse est que les doubles ne sont PAS des nombres réels (R), comme cela est indiqué dans la dernière partie de cette réponse. Ce sont des nombres à virgule flottante, et le PO essaie d'appliquer un raisonnement de nombre réel à quelque chose qui n'est pas un nombre réel. Ils semblent similaires la plupart du temps parce qu'ils ont été conçus pour être similaires, mais ils sont fondamentalement différents. Les doubles définissent quelque chose appelé NaN "Pas un numéro", (suite...)

2 votes

(suite...) qui serait un "résultat" plus mathématiquement correct s'il s'agissait en fait de nombres réels. Pourtant, il n'a pas retourné NaN. La raison est à peu près la même que celle décrite dans la réponse : parce qu'en logique à virgule flottante, on suppose généralement que "0,0" est un très petit nombre. Vous ne pouvez cependant pas dire qu'il es un petit nombre, en déclarant qu'il y a es et la représentation exacte de zéro est trompeuse, car il n'existe pas de correspondance 1 à 1 entre les valeurs flottantes et les valeurs réelles. Au contraire, chaque valeur flottante correspond à une gamme de valeurs réelles, et la valeur flottante "0,0" comprend à la fois réel zéro et une série d'autres petites valeurs.

0 votes

Un autre exemple de la différence fondamentale entre les nombres à virgule flottante et les nombres réels est que les nombres à virgule flottante définissent "-0.0" (zéro négatif), et si OP avait divisé par cette valeur, le résultat aurait été le suivant Negative Infinity . Pourtant, que pensez-vous 0.0 == -0.0 évalue à ?

8voto

heisenberg Points 6120

Un double est un nombre à virgule flottante et non une valeur exacte, donc ce par quoi vous divisez réellement du point de vue du compilateur est quelque chose qui s'approche de zéro, mais pas exactement zéro.

1 votes

En fait, les doubles ont une représentation d'une valeur qui est exactement zéro. La véritable raison est que, par définition, la division par zéro d'un double donne la valeur Inf - c'est un choix délibéré et non un accident.

2 votes

@slebetman - Si les doubles ont " une représentation d'une valeur qui est exactement zéro ", alors pourquoi les doubles font-ils la distinction entre " +0 " et " -0 " et pourquoi 1/+0 et 1/-0 donnent-ils des résultats différents ? L'idée d'un "zéro signé" n'a de sens que si ces valeurs sont considérées comme des valeurs positives ou négatives trop petites pour être représentées normalement. Notez qu'il n'existe pas de zéro non signé dans les types à virgule flottante IEEE 754.

1 votes

@Jeffrey : +Même si vous affirmez que les nombres plus petits que epsilon sont représentés par 0, vous dites toujours que les nombres trop petits sont effectivement 0. Oui, en mathématiques, -0 n'a aucun sens, mais lorsque le 754 a été conçu, les physiciens effectuant des simulations ont fait valoir qu'ils voulaient savoir de quelle direction venait un résultat si la limite d'un calcul menait à 0.

2voto

Abacus Points 499

Car la virgule flottante "numérique" n'est rien de tel. Opérations en virgule flottante :

  • ne sont pas associatives
  • ne sont pas distributifs
  • ne peut pas avoir d'inverse multiplicatif

(voir http://www.cs.uiuc.edu/class/fa07/cs498mjg/notes/floating-point.pdf pour quelques exemples)

La virgule flottante est une construction destinée à résoudre un problème spécifique, et elle est utilisée partout alors qu'elle ne devrait pas l'être. Je pense qu'ils sont assez horribles, mais c'est subjectif.

2voto

Wesley Wiser Points 3676

C'est à dessein, car le double est conforme à IEEE 754 la norme pour l'arithmétique à virgule flottante. Consultez la documentation de Double.NegativeInfinity y Double.PositiveInfinity .

La valeur de cette constante est le résultat de la division d'un nombre positif {ou négatif} par zéro.

1voto

Brennan Vincent Points 1894

Cela a probablement quelque chose à voir avec le fait que les nombres à virgule flottante de la norme IEEE et les nombres à virgule flottante en double précision ont une valeur "infinie" spécifiée. .NET ne fait qu'exposer quelque chose qui existe déjà, au niveau du matériel.

Voir la réponse de kekekela pour savoir pourquoi cela a du sens, logiquement.

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