44 votes

Pourquoi les opérateurs C/C++ <, <= et == renvoient-ils vrai si l'un des arguments est NaN ?

D'après ce que je comprends des règles des comparaisons en virgule flottante IEEE-754, tous les opérateurs de comparaison, à l'exception de != retournera false si l'un ou l'autre ou les deux arguments sont des NaN, tandis que la fonction != retournera vrai. Je peux facilement reproduire ce comportement avec un simple test standalone :

for (int ii = 0; ii < 4; ++ii)
{
    float a = (ii & 1) != 0 ? NAN : 1.0f;
    float b = (ii & 2) != 0 ? NAN : 2.0f;
    #define TEST(OP) printf("%4.1f %2s %4.1f => %s\n", a, #OP, b, a OP b ? "true" : "false");
    TEST(<)
    TEST(>)
    TEST(<=)
    TEST(>=)
    TEST(==)
    TEST(!=)
}

Ceci imprime les résultats attendus : (NaN est formaté en tant que -1.$ dans le runtime MSVC)

 1.0  <  2.0 => true
 1.0  >  2.0 => false
 1.0 <=  2.0 => true
 1.0 >=  2.0 => false
 1.0 ==  2.0 => false
 1.0 !=  2.0 => true
-1.$  <  2.0 => false
-1.$  >  2.0 => false
-1.$ <=  2.0 => false
-1.$ >=  2.0 => false
-1.$ ==  2.0 => false
-1.$ !=  2.0 => true
 1.0  < -1.$ => false
 1.0  > -1.$ => false
 1.0 <= -1.$ => false
 1.0 >= -1.$ => false
 1.0 == -1.$ => false
 1.0 != -1.$ => true
-1.$  < -1.$ => false
-1.$  > -1.$ => false
-1.$ <= -1.$ => false
-1.$ >= -1.$ => false
-1.$ == -1.$ => false
-1.$ != -1.$ => true

Cependant, lorsque je colle ce morceau de code dans les profondeurs des boucles internes de mon application, où tous les calculs en virgule flottante sont effectués, j'obtiens ces résultats inexplicables :

 1.0  <  2.0 => true
 1.0  >  2.0 => false
 1.0 <=  2.0 => true
 1.0 >=  2.0 => false
 1.0 ==  2.0 => false
 1.0 !=  2.0 => true
-1.$  <  2.0 => true
-1.$  >  2.0 => false
-1.$ <=  2.0 => true
-1.$ >=  2.0 => false
-1.$ ==  2.0 => true
-1.$ !=  2.0 => false
 1.0  < -1.$ => true
 1.0  > -1.$ => false
 1.0 <= -1.$ => true
 1.0 >= -1.$ => false
 1.0 == -1.$ => true
 1.0 != -1.$ => false
-1.$  < -1.$ => true
-1.$  > -1.$ => false
-1.$ <= -1.$ => true
-1.$ >= -1.$ => false
-1.$ == -1.$ => true
-1.$ != -1.$ => false

Pour une raison quelconque, le < , <= y == renvoient inopinément un résultat vrai lorsque l'un ou les deux arguments sont des NaN. De plus, les != renvoie inopinément un faux.

Il s'agit de code 64 bits, construit avec Visual Studio 2010, fonctionnant sur un Intel Xeon E5-2650. Utilisation de _mm_getcsr() J'ai confirmé que le registre CSR a la même valeur dans les deux scénarios.

Qu'est-ce qui pourrait encore influencer le comportement des mathématiques à virgule flottante de cette manière ?

54voto

Sean Points 711

Ce comportement est dû à la /fp:fast Option du compilateur MSVC, qui (entre autres choses) permet au compilateur d'effectuer des comparaisons sans tenir compte du comportement NaN approprié dans le but de générer un code plus rapide. Utilisation de /fp:precise o /fp:strict au lieu de cela, ces comparaisons se comportent comme prévu lorsqu'elles sont présentées avec des arguments NaN.

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