为什么 NaN - NaN == 0.0 与英特尔 C++ 编译器?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/32195949/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why does NaN - NaN == 0.0 with the Intel C++ Compiler?
提问by imallett
It is well-known that NaNs propagate in arithmetic, but I couldn't find any demonstrations, so I wrote a small test:
众所周知,NaNs 在算术中传播,但是我找不到任何演示,所以我写了一个小测试:
#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;
}
The example (running live here) produces basically what I would expect (the negative is a little weird, but it kind of makes sense):
示例(在此处运行)基本上产生了我所期望的(否定有点奇怪,但它有点道理):
neg: -nan
sub: nan nan nan
add: nan nan
div: nan nan nan
mul: nan nan
MSVC 2015 produces something similar. However, Intel C++ 15 produces:
MSVC 2015 产生了类似的东西。但是,英特尔 C++ 15 产生:
neg: -nan(ind)
sub: nan nan 0.000000
add: nan nan
div: nan nan nan
mul: nan nan
Specifically, qNaN - qNaN == 0.0
.
具体来说,qNaN - qNaN == 0.0
。
This... can't be right, right? What do the relevant standards (ISO C, ISO C++, IEEE 754) say about this, and why is there a difference in behavior between the compilers?
这……不可能吧?相关标准(ISO C、ISO C++、IEEE 754)对此有何评论,为什么编译器之间的行为存在差异?
回答by Petr Abdulin
The default floating point handling in Intel C++ compiler is /fp:fast
, which handles NaN
's unsafely (which also results in NaN == NaN
being true
for example). Try specifying /fp:strict
or /fp:precise
and see if that helps.
默认浮点在英特尔C ++编译器处理是/fp:fast
,该手柄NaN
的不安全(其也导致NaN == NaN
被true
例如)。尝试指定/fp:strict
或/fp:precise
查看是否有帮助。
回答by ouah
This . . . can't be right, right? My question: what do the relevant standards (ISO C, ISO C++, IEEE 754) say about this?
这个 。. . 不可能是对的,对吧?我的问题:相关标准(ISO C、ISO C++、IEEE 754)对此有何评论?
Petr Abdulin already answered why the compiler gives a 0.0
answer.
Petr Abdulin 已经回答了为什么编译器会给出0.0
答案。
Here is what IEEE-754:2008 says:
这是 IEEE-754:2008 所说的:
(6.2 Operations with NaNs) "[...] For an operation with quiet NaN inputs, other than maximum and minimum operations, if a floating-point result is to be delivered the result shall be a quiet NaN which should be one of the input NaNs."
(6.2 带 NaN 的操作) "[...] 对于具有安静 NaN 输入的操作,最大和最小操作除外,如果要传递浮点结果,则结果应为安静 NaN,它应该是输入 NaN。”
So the only valid result for the subtraction of two quiet NaN operand is a quiet NaN; any other result is not valid.
所以两个安静的 NaN 操作数相减的唯一有效结果是一个安静的 NaN;任何其他结果都无效。
The C Standard says:
C标准说:
(C11, F.9.2 Expression transformations p1) "[...]
x ? x → 0. 0 "The expressions x ? x and 0. 0 are not equivalent if x is a NaN or infinite"
(C11,F.9.2 表达式转换 p1)“[...]
X ?x → 0. 0 “如果 x 是 NaN 或无穷大,则表达式 x ? x 和 0. 0 不等价”
(where here NaN denotes a quiet NaN as per F.2.1p1 "This specification does not define the behavior of signaling NaNs. It generally uses the term NaN to denote quiet NaNs")
(这里的 NaN 表示按照 F.2.1p1 “这个规范没有定义信号 NaN 的行为。它通常使用术语 NaN 来表示安静的 NaN”)
回答by zwol
Since I see an answer impugning the standards compliance of Intel's compiler, and no one else has mentioned this, I will point out that both GCC and Clang have a mode in which they do something quite similar. Their default behavior is IEEE-compliant —
由于我看到一个质疑英特尔编译器标准合规性的答案,而没有其他人提到这一点,我将指出 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
— but if you ask for speed at the expense of correctness, you get what you ask for —
——但如果你以牺牲正确性为代价来要求速度,你就会得到你所要求的——
$ 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
I think it is entirely fair to criticize ICC's choice of default, but I would not read the entire Unix wars back into that decision.
我认为批评 ICC 对default的选择是完全公平的,但我不会将整个 Unix War重新解读为该决定。