299 votes

Pourquoi `NaN - NaN == 0.0` ?

Il est bien connu que les NaNs se propagent dans l'arithmétique. Mais, je n'ai pas trouvé de démonstration. Alors, j'ai é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 direct ici ) produit essentiellement ce à quoi je m'attendais (le négatif est un peu bizarre, mais il a un 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, n'est-ce pas ? Ma question : que disent les normes pertinentes (ISO C, ISO C++, IEEE 754) à ce sujet ?

299voto

Petr Abdulin Points 7297

Le traitement par défaut de la virgule flottante dans le compilateur Intel C++ est le suivant /fp:fast qui gère NaN de manière non sécurisée (ce qui entraîne également l'apparition de NaN == NaN être true par exemple). Essayez de spécifier /fp:strict ou /fp:precise et voir si ça aide.

15voto

Paul Points 5437

Je n'ai pas votre compilateur, mais ceux que j'ai semblent corrects.

Ubuntu 15.04

gcc sur Linux ne donne pas de zéros.

g++ --version
g++ (Ubuntu 4.9.2-10ubuntu13) 4.9.2
g++ nan.c++ -o nan
./nan
neg: -nan
sub: nan nan nan
add: nan nan
div: nan nan nan
mul: nan nan

similaire avec clang sur Linux

rm ./nan
clang --version
Ubuntu clang version 3.6.0-2ubuntu1 (tags/RELEASE_360/final) (based on LLVM 3.6.0)
Target: x86_64-pc-linux-gnu
Thread model: posix
clang nan.c++ -o nan
./nan
neg: -nan
sub: nan nan nan
add: nan nan
div: nan nan nan
mul: nan nan

7voto

Serj.by Points 1

Même chose sur Mac OS (Yosemite) :

mac:~ $ clang nan.cpp -o nan
mac:~ $ ./nan
neg: nan
sub: nan nan nan
add: nan nan
div: nan nan nan
mul: nan nan

$ clang --version    
Apple LLVM version 6.1.0 (clang-602.0.53) (based on LLVM 3.6.0svn)
Target: x86_64-apple-darwin14.5.0
Thread model: posix

Encore mieux - il n'y a pas de -nan ce qui est un non-sens aussi bien que 0.

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