J'étais membre du comité IEEE-754, 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 à virgule flottante ne satisfait pas les axiomes de l'arithmétique réelle. La trichotomie n'est pas la seule propriété de l'arithmétique réelle qui ne tient pas pour les flotteurs, ni même la plus importante. Par exemple:
- L'addition n'est pas associative.
- La loi distributive ne tient pas.
- Il existe des nombres à virgule flottante sans inverses.
Je pourrais continuer. Il n'est pas possible de spécifier un type arithmétique de taille fixe qui satisfait toutes les propriétés de l'arithmétique réelle que nous connaissons et aimons. Le comité 754 doit décider de plier ou de casser certains d'entre eux. Ceci est guidé par des principes assez simples:
- Lorsque nous le pouvons, nous faisons correspondre le comportement de l'arithmétique réelle.
- Lorsque nous ne pouvons pas, nous essayons de rendre les violations aussi prévisibles et aussi faciles à diagnostiquer que possible.
En ce qui concerne votre commentaire "cela ne signifie pas que la bonne réponse est fausse", c'est faux. Le prédicat (y < x)
demande si y
est inférieur à x
. Si y
est NaN, il n'est pas inférieur à toute valeur à virgule flottante x
, donc la réponse est nécessairement fausse.
J'ai mentionné que la trichotomie ne s'applique pas aux valeurs à virgule flottante. Cependant, il existe une propriété similaire qui tient. Article 5.11, paragraphe 2 de la norme 754-2008:
Quatre relations mutuellement exclusives sont possibles: inférieure à, égale, supérieure à et non ordonnée. Le dernier cas se présente quand au moins un opérande est NaN. Chaque NaN comparera sans ordre avec tout, y compris lui-même.
En ce qui concerne l'écriture de code supplémentaire pour gérer les NaN, il est généralement possible (mais pas toujours facile) de structurer votre code de manière à ce que les NaN passent correctement, mais ce n'est pas toujours le cas. Dans le cas contraire, un code supplémentaire peut être nécessaire, mais c'est un petit prix à payer pour la commodité que la fermeture algébrique a apportée à l'arithmétique à virgule flottante.
Addendum: De nombreux commentateurs ont fait valoir qu'il serait plus utile de préserver la réflexivité de l'égalité et de la trichotomie au motif que l'adoption de NaN! = NaN ne semble conserver aucun axiome familier. J'avoue avoir une certaine sympathie pour ce point de vue, alors j'ai pensé que je reviendrais sur cette réponse et fournirais un peu plus de contexte.
D'après ce que j'ai compris en parlant à Kahan, NaN! = NaN est né de deux considérations pragmatiques:
Cela x == y
devrait être équivalent à x - y == 0
chaque fois que possible (au-delà d'être un théorème de l'arithmétique réelle, cela rend l'implémentation matérielle de la comparaison plus efficace en termes d'espace, ce qui était de la plus haute importance au moment où la norme a été élaborée - notez cependant que cela est violé pour x = y = l'infini, ce n'est donc pas une bonne raison en soi; il aurait pu être raisonnablement plié (x - y == 0) or (x and y are both NaN)
).
Plus important encore, il n'y avait pas de isnan( )
prédicat au moment où NaN a été formalisé dans l'arithmétique 8087; il était nécessaire de fournir aux programmeurs un moyen pratique et efficace de détecter les valeurs NaN qui ne dépendaient pas des langages de programmation fournissant quelque chose comme cela isnan( )
qui pourrait prendre de nombreuses années. Je citerai les propres écrits de Kahan sur le sujet:
S'il n'y avait aucun moyen de se débarrasser des NaN, ils seraient aussi inutiles que les indéfinis sur les CRAY; dès que l'on en rencontrait un, il serait préférable d'arrêter le calcul plutôt que de le poursuivre pendant une durée indéterminée jusqu'à une conclusion indéfinie. C'est pourquoi certaines opérations sur les NaN doivent fournir des résultats non-NaN. Quelles opérations? … Les exceptions sont les prédicats C «x == x» et «x! = X», qui sont respectivement 1 et 0 pour chaque nombre infini ou fini x mais inversés si x n'est pas un nombre (NaN); ceux-ci fournissent la seule distinction simple et non exceptionnelle entre les NaN et les nombres dans les langues qui n'ont pas de mot pour NaN et un prédicat IsNaN (x).
Notez que c'est également la logique qui exclut le retour de quelque chose comme un «Not-A-Boolean». Peut-être que ce pragmatisme était déplacé et que la norme aurait dû être exigée isnan( )
, mais cela aurait rendu NaN presque impossible à utiliser efficacement et commodément pendant plusieurs années alors que le monde attendait l'adoption du langage de programmation. Je ne suis pas convaincu que cela aurait été un compromis raisonnable.
Pour être franc: le résultat de NaN == NaN ne va pas changer maintenant. Mieux vaut apprendre à vivre avec que de se plaindre sur Internet. Si vous voulez faire valoir qu'une relation d'ordre appropriée pour les conteneurs devrait également exister, je recommanderais de recommander que votre langage de programmation préféré implémente le totalOrder
prédicat normalisé dans IEEE-754 (2008). Le fait qu'il n'ait pas déjà témoigné de la validité de l'inquiétude de Kahan qui a motivé l'état actuel des choses.
while (fabs(x - oldX) > threshold)
, sortant de la boucle si la convergence se produit ou si un NaN entre dans le calcul. La détection du NaN et du remède approprié se ferait alors en dehors de la boucle.