Il est bien connu que les NaN se propagent en arithmétique, mais je n'ai trouvé aucune démonstration, j'ai donc écrit un petit test:
#include <limits>
#include <cstdio>
int main(int argc, char* argv[]) {
float qNaN = std::numeric_limits<float>::quiet_NaN();
float neg = -qNaN;
float sub1 = 6.0f - qNaN;
float sub2 = qNaN - 6.0f;
float sub3 = qNaN - qNaN;
float add1 = 6.0f + qNaN;
float add2 = qNaN + qNaN;
float div1 = 6.0f / qNaN;
float div2 = qNaN / 6.0f;
float div3 = qNaN / qNaN;
float mul1 = 6.0f * qNaN;
float mul2 = qNaN * qNaN;
printf(
"neg: %f\nsub: %f %f %f\nadd: %f %f\ndiv: %f %f %f\nmul: %f %f\n",
neg, sub1,sub2,sub3, add1,add2, div1,div2,div3, mul1,mul2
);
return 0;
}
L'exemple (en cours d'exécution ici ) produit essentiellement ce à quoi je m'attendais (le négatif est un peu bizarre, mais cela a du sens):
neg: -nan
sub: nan nan nan
add: nan nan
div: nan nan nan
mul: nan nan
MSVC 2015 produit quelque chose de similaire. Cependant, Intel C ++ 15 produit:
neg: -nan(ind)
sub: nan nan 0.000000
add: nan nan
div: nan nan nan
mul: nan nan
Plus précisément, qNaN - qNaN == 0.0
.
Cela ... ne peut pas être vrai, non? Que disent les normes pertinentes (ISO C, ISO C ++, IEEE 754) à ce sujet, et pourquoi y a-t-il une différence de comportement entre les compilateurs?
Nan-NaN
estNaN
. Perl et Scala se comportent également de la même manière.-ffast-math
sur gcc)?Réponses:
La valeur par défaut à virgule flottante de manipulation dans le compilateur Intel C
/fp:fast
, qui traite deNaN
l » unsafely (qui a également conduit àNaN == NaN
êtretrue
par exemple). Essayez de spécifier/fp:strict
ou/fp:precise
et voyez si cela aide.la source
/fp:fast
: si vous voulez quelque chose de sûr , vous devriez probablement éviter de voir des NaN apparaître en premier lieu, et ne les utilisez généralement pas==
avec des nombres à virgule flottante. S'appuyer sur la sémantique bizarre que IEEE754 assigne à NaN demande des ennuis.NaN==NaN
revenirfalse
?Ce . . . ne peut pas avoir raison, non? Ma question: qu'en disent les normes pertinentes (ISO C, ISO C ++, IEEE 754)?
Petr Abdulin a déjà répondu pourquoi le compilateur donne une
0.0
réponse.Voici ce que dit IEEE-754: 2008:
Ainsi, le seul résultat valide pour la soustraction de deux opérandes NaN silencieux est un NaN silencieux; tout autre résultat n'est pas valide.
La norme C dit:
(où ici NaN désigne un NaN silencieux selon F.2.1p1 "Cette spécification ne définit pas le comportement des NaN de signalisation. Elle utilise généralement le terme NaN pour désigner des NaN silencieux")
la source
Puisque je vois une réponse contestant la conformité aux normes du compilateur d'Intel, et personne d'autre ne l'a mentionné, je soulignerai que GCC et Clang ont un mode dans lequel ils font quelque chose de très similaire. Leur comportement par défaut est conforme IEEE -
- mais si vous demandez de la vitesse au détriment de l'exactitude, vous obtenez ce que vous demandez -
Je pense qu'il est tout à fait juste de critiquer le choix par défaut d'ICC , mais je ne relirais pas l'intégralité des guerres Unix dans cette décision.
la source
-ffast-math
,gcc
n'est plus conforme à ISO 9899: 2011 en ce qui concerne l'arithmétique à virgule flottante.