c++ - 判断nan - 半精度浮点数计算




为什么使用英特尔C++编译器的NaN-NaN== 0.0? (2)

因为我看到一个答案损害了英特尔编译器的标准兼容性,而且没有人提到这一点,所以我要指出,GCC和Clang都有一种执行类似操作的模式。 它们的默认行为符合IEEE标准-

$ g++ -O2 test.cc && ./a.out 
neg: -nan
sub: nan nan nan
add: nan nan
div: nan nan nan
mul: nan nan

$ clang++ -O2 test.cc && ./a.out 
neg: -nan
sub: -nan nan nan
add: nan nan
div: nan nan nan
mul: nan nan

—但是,如果您以牺牲正确性为代价要求速度,那么您会得到所要求的—

$ g++ -O2 -ffast-math test.cc && ./a.out 
neg: -nan
sub: nan nan 0.000000
add: nan nan
div: nan nan 1.000000
mul: nan nan

$ clang++ -O2 -ffast-math test.cc && ./a.out 
neg: -nan
sub: -nan nan 0.000000
add: nan nan
div: nan nan nan
mul: nan nan

我认为批评ICC选择 默认 是完全公平的,但是我不会将整个Unix战争重新读回该决定。

众所周知,NaN会以算术方式传播,但是我找不到任何演示,因此我编写了一个小测试:

#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;
}

该示例( 在此处实时运行 )基本上产生了我所期望的(否定有点怪异,但有点道理):

neg: -nan
sub: nan nan nan
add: nan nan
div: nan nan nan
mul: nan nan

MSVC 2015产生类似的结果。 但是,英特尔C ++ 15会产生:

neg: -nan(ind)
sub: nan nan 0.000000
add: nan nan
div: nan nan nan
mul: nan nan

具体地, qNaN - qNaN == 0.0

这个...不可能是吧? 有关标准(ISO C,ISO C ++,IEEE 754)对此有何评论?为什么编译器之间的行为有所不同?


英特尔C ++编译器中的默认浮点处理是 /fp:fast ,它不安全地处理 NaN (例如,这还会导致 NaN == NaNtrue )。 尝试指定 /fp:strict/fp:precise ,看看是否有帮助。







icc