250 votes

Quelle est la justification pour toutes les comparaisons, retournant la valeur false pour les valeurs IEEE754 NaN ?

Pourquoi faire des comparaisons de valeurs NaN se comporter différemment de toutes les autres valeurs? C'est, de toutes les comparaisons avec les opérateurs ==, <=, >=, <, > lorsque l'une ou les deux valeurs est NaN renvoie la valeur false, contrairement au comportement de toutes les autres valeurs.

Je suppose que cela simplifie les calculs numériques, d'une certaine façon, mais je ne trouve pas explicitement indiqué raison, pas même dans les Notes de cours sur le Statut de la norme IEEE 754 par Kahan qui aborde d'autres décisions de conception en détail.

Ce comportement déviant est à l'origine de la difficulté quand on fait simple de traitement de données. Par exemple, lors du tri d'une liste d'enregistrements w.r.t. certaines valeurs réelles de terrain dans un programme C j'ai besoin d'écrire du code supplémentaire pour gérer NaN que la durée maximale de l'élément, sinon l'algorithme de tri pourrait devenir confus.

Edit: Les réponses jusqu'à présent, tous affirment qu'il est vain de comparer les NaNs.

Je suis d'accord, mais cela ne signifie pas que la bonne réponse est fausse, il doit plutôt être un Pas-un-Booléen (NaB), qui, heureusement, n'existe pas.

Donc, le choix de retourner true ou false pour les comparaisons est de mon point de vue arbitraire, et pour les données générales de traitement, il serait avantageux si elle obéit aux lois habituelles (la réflexivité de ==, trichotomie de <, ==, >), de peur que les structures de données qui s'appuient sur ces lois de devenir confus.

Donc, je suis en demandant certains avantage concret de violation de ces lois, et pas seulement la pensée philosophique.

Edit 2: Je crois que je comprends maintenant pourquoi faire NaN maximale serait une mauvaise idée, ce serait gâcher le calcul de la limite supérieure.

NaN != NaN peut être souhaitable afin d'éviter la détection de la convergence dans une boucle comme

while (x != oldX) {
    oldX = x;
    x = better_approximation(x);
}

qui, cependant, devraient être mieux écrite par comparaison de la valeur absolue de la différence avec une petite limite. Donc, à mon humble avis, ce qui est relativement faible argument pour casser la réflexivité à NaN.

501voto

Stephen Canon Points 58003

J'ai été membre de l'IEEE-754 comité, je vais essayer de clarifier un peu les choses.

Tout d'abord, les nombres à virgule flottante ne sont pas des nombres réels, et l'arithmétique en virgule flottante n'a pas satisfait les axiomes de l'arithmétique réelle. Trichotomie n'est pas la seule propriété de l'arithmétique réelle qui ne fonctionne pas pour les chars, ni même le plus important. Par exemple:

  • L'Addition est associative.
  • La loi de distributivité ne tient pas.
  • Il y a des nombres à virgule flottante sans inverses.

Je pourrais continuer. Il n'est pas possible de spécifier une taille fixe de l'arithmétique type qui satisfait toutes les propriétés de l'arithmétique réelle que nous connaissons et aimons. 754 comité doit décider de plier ou de casser quelques-uns d'entre eux. C'est guidé par une jolie principes simples:

  1. Lorsque nous le pouvons, nous faisons correspondre le comportement de l'arithmétique réelle.
  2. Quand nous ne le pouvons, nous essayons de rendre les violations prévisible et facile à diagnostiquer que possible.

Concernant votre commentaire "cela ne veut pas dire que la bonne réponse est "faux", c'est faux. Le prédicat (y < x) demande si y est inférieure à x. Si y est NaN, il est pas inférieure à toute valeur à virgule flottante x, donc la réponse est nécessairement faux.

Je l'ai mentionné que trichotomie ne fonctionne pas pour les valeurs à virgule flottante. Cependant, il est une propriété qui ne maintenez-la enfoncée. La Clause 5.11, alinéa 2, de la 754-2008 standard:

Quatre mutuellement exclusifs relations sont possibles: inférieur à, égal à, supérieur à, et non ordonnée. Le dernier cas de figure se présente lorsque au moins un des opérandes est NaN. Chaque NaN compare non ordonnée avec tout, y compris lui-même.

Aussi loin que d'écrire du code supplémentaire pour gérer les NaNs va, il est généralement possible (bien que pas toujours facile) à la structure de votre code de telle façon que NaNs automne correctement, mais ce n'est pas toujours le cas. Quand il n'est pas certain code supplémentaire peut être nécessaire, mais c'est un petit prix à payer pour la commodité qui algébrique fermeture apporté à l'arithmétique en virgule flottante.


Addendum: De nombreux commentateurs ont fait valoir qu'il serait plus utile pour préserver la réflexivité, de l'égalité et de la trichotomie au motif que l'adoption NaN != NaN ne semble pas pour préserver le familier axiome. J'avoue avoir une certaine sympathie pour ce point de vue, alors j'ai pensé que je voudrais revoir cette réponse et de fournir un peu plus de contexte.

Ma compréhension de parler à Kahan est que NaN != NaN né de deux considérations pragmatiques:

  • qu' x == y doit être équivalent à x - y == 0 chaque fois que possible (au-delà d'être un théorème d'arithmétique réelle, ce qui rend le matériel de mise en œuvre de comparaison plus efficace en terme d'espace, ce qui était de la plus haute importance au moment de la norme a été élaborée note, cependant, que c'est violée pour x = y = infini, il n'est donc pas une bonne raison; il pouvait raisonnablement tordue x - y == 0 or NaN).

  • plus important encore, il n'y avait pas isnan( ) prédicat au moment de la NaN a été formalisé dans la 8087 l'arithmétique; il était nécessaire de fournir des programmeurs avec un pratique et efficace des moyens de détection NaN valeurs qui ne dépendent pas des langages de programmation offrant quelque chose comme isnan( ) qui pourrait prendre de nombreuses années. Je vais vous citer Kahan propre écriture sur le sujet:

Ont été il y a pas moyen de se débarrasser de NaNs, ils seraient aussi inutile que Indefinites sur les CRAYs; dès que l'on s'étaient rencontrés, le calcul serait le meilleur arrêté plutôt que de suite pour une durée indéterminée à durée Indéterminée conclusion. C'est pourquoi certaines opérations sur NaNs doit fournir non-NaN résultats. Quelles opérations? ... À l'exception de C prédicats "x == x" et " x != x ", qui sont respectivement 1 et 0 pour chaque infinie ou finie nombre x mais à l'inverse si x n'est Pas un Nombre ( NaN ); elles constituent l'unique simple, rien d'exceptionnel distinction entre NaNs et des numéros dans des langues qui n'ont pas de mot pour NaN et d'un prédicat IsNaN(x).

Notez que c'est également la logique qui exclut le retour à quelque chose comme un "Pas-A-Booléen". Peut-être que ce pragmatisme a été égaré, et le standard aurait exigé isnan( ), mais qui aurait fait NaN presque impossible de l'utiliser, efficace et pratique pour plusieurs années, tout le monde attendait pour le langage de programmation de l'adoption. Je ne suis pas convaincu que cela aurait été un compromis raisonnable.

Pour être clair: le résultat de NaN == NaN ne va pas changer maintenant. Mieux vaut apprendre à vivre avec elle que de se plaindre sur internet. Si vous voulez faire valoir qu'un ordre de relation adapté pour les conteneurs doit également exister, je vous conseille de plaider pour que votre langage de programmation favori de mettre en œuvre l' totalOrder prédicat normalisée la norme IEEE-754 (2008). Le fait qu'il n'a pas parle déjà de la validité de Kahan est une préoccupation qui a motivé l'état actuel des choses.

50voto

Chris Points 151

NaN peut être considéré comme un état indéfini/nombre. similaire à la notion de 0/0 est indéfini ou sqrt(-3) (dans le nombre réel système où le floating point de vie).

NaN est utilisé comme une sorte d'espace réservé pour cet état indéfini. Mathématiquement parlant, l'indéfini n'est pas égal à undefined. Vous ne pouvez pas dire une valeur non définie est supérieure ou inférieure à une autre valeur non définie. Par conséquent, toutes les comparaisons de retour faux.

Ce comportement est également avantageuse dans le cas où vous comparez sqrt(-3) sqrt(-2). Ils retournent NaN mais ils ne sont pas équivalentes, même si elles renvoient la même valeur. Par conséquent, l'égalité renvoie toujours false lorsque vous traitez avec NaN est le comportement souhaité.

36voto

Jack Ryan Points 5257

Jeter dans encore une autre analogie. Si je vous remettre deux boîtes et vous dire qu’aucun d’eux contient une pomme, serait me dire que les boîtes contiennent la même chose ?

NaN ne contient aucune information sur ce que quelque chose est, juste ce qu’il n’est pas. C’est pourquoi ces éléments peuvent jamais définitivement dire égal.

12voto

Stefan Rusek Points 2437

À partir de l'article de wikipédia sur NaN, les pratiques suivantes peuvent provoquer des NaNs:

  • Toutes les opérations mathématiques> avec un NaN au moins un opérande
  • Les divisions 0/0, ∞/∞, ∞/-∞, -∞/∞, et -∞/-∞
  • Les multiplications 0×∞ et 0×-∞
  • Les ajouts ∞ + (-∞), (-∞) + ∞ et l'équivalent de soustractions.
  • L'application d'une fonction à des arguments en dehors de son domaine, y compris en prenant la racine carrée d'un nombre négatif, prenant le logarithme d'un nombre négatif, en prenant la tangente d'un multiple impair de 90 degrés (ou π/2 radians), ou en prenant l'inverse du sinus ou cosinus d'un nombre qui est inférieur à -1 ou supérieure à +1.

Depuis il n'y a aucun moyen de savoir lequel de ces opérations NaN, il n'y a aucun moyen de comparer entre eux qui fait sens.

2voto

Christian Hayter Points 17999

Il ne semble que la singulière plupart des environnements de programmation qui permettent de NaNs n’autorisent pas aussi logique à 3 valeurs. Si vous jetez 3 valeur logique dans le mélange, elle devient cohérente :

  • (2,7 == 2,7) = true
  • (2,7 == 2.6) = false
  • (2,7 == NaN) = inconnu
  • (NaN == NaN) = inconnu

Même .NET ne fournit pas un opérateur, donc vous êtes toujours bloqué avec le silly résultat.

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