Pourquoi NaN (pas un nombre) est-il uniquement disponible pour les doubles?

J’ai une classe métier qui contient deux propriétés décimales nullables. Une troisième propriété renvoie le résultat de la multiplication des deux autres propriétés. Si HasValue est vrai pour les deux types NULL, je multiplie et retourne le résultat. J’ai quelques options pour la valeur de retour si une ou les deux propriétés sont nulles:

  • Retour 0
  • Jeter une exception
  • Retourne un nombre magique (-1)
  • Retourne décimal? (EDIT – voir les commentaires)

Je pensais que l’une de mes options serait de renvoyer NaN, mais je constate que cela n’est possible que pour le type double. Pourquoi est-ce?

Pour mémoire, le fait de retourner 0 fait le plus de sens dans ce cas et c’est ce que je compte faire à moins que quelqu’un ait une meilleure suggestion.

Les types intégraux dans .NET utilisent le système de complément à deux pour la représentation. Bien qu’ils puissent réserver des modèles de bits pour des valeurs spéciales, ils ont choisi de ne pas le faire. double et float utilisent un système de représentation complètement différent (IEEE 754) qui réserve des motifs de bits spéciaux pour NaN, + Infinity, -Infinity, …

Une des raisons pour lesquelles les valeurs NaN et Infinity ont plus de sens pour l’arithmétique en virgule flottante est que les opérations peuvent entraîner une division par zéro, non seulement parce que le diviseur est nul mais trop petit pour être représenté par le type. Par conséquent, si ce n’était pas le cas, vous pourriez avoir un calcul valide qui jetterait mystérieusement une exception par zéro. Cela n’arrivera pas pour les types int car ils sont exacts et ne comportent pas d’erreur de précision.

decimal est conçu pour être utilisé pour les nombres décimaux décimaux «du monde réel». Il est rarement sujet aux calculs que le double et le float sont conçus pour faire. Qu’est-ce que NaN exprimerait pour un nombre réel?

Laissant les raisons derrière tout cela, c’est ce que c’est et il n’y a rien à faire, donc la meilleure voie à suivre est d’utiliser des types nullables (ils sont conçus pour aider exactement avec ce genre de situation). C’est la bonne façon de résoudre ce problème. Si vous ne voulez pas faire cela (et que les exceptions n’ont pas de sens), vous devriez avoir recours à la solution des nombres magiques. Si vous avez choisi de le faire, assurez-vous simplement qu’il est hors du domaine des résultats valides.

EDIT (idée fausse très répandue sur les décimales):

Comme noté également par MSDN , decimal n’est pas un point fixe. C’est un nombre à virgule flottante:

Un nombre décimal est une valeur à virgule flottante composée d’un signe, d’une valeur numérique comprise entre 0 et 9 et d’un facteur d’échelle indiquant la position d’un point décimal flottant qui sépare les parties intégrale et fractionnaire de la valeur numérique.

Pour résoudre NAN et Infinity, utilisez ceci

 if (Double.IsNaN(YourValue) || Double.IsInfinity(YourValue)) { YourValue = 0; }