为什么NaN - NaN == 0.0与Intel c++编译器
Why does NaN - NaN == 0.0 with the Intel C++ Compiler?
大家都知道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: %fnsub: %f %f %fnadd: %f %fndiv: %f %f %fnmul: %f %fn",
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产生了类似的东西。然而,Intel 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)对此有何规定?为什么在编译器之间存在行为差异?
Intel c++编译器中的默认浮点处理是/fp:fast
,它不安全地处理NaN
(这也导致NaN == NaN
为true
)。尝试指定/fp:strict
或/fp:precise
,看看是否有帮助。
这个…不可能是对的,对吧?我的问题是:相关标准(ISO C、ISO c++、IEEE 754)对此有何规定?
Petr Abdulin已经回答了为什么编译器给出了0.0
的答案。
以下是IEEE-754:2008的规定:
(6.2 nan操作)"[…]对于具有安静NaN输入的操作,除最大值和最小值操作外,如果要传递浮点结果,则结果应是一个应该是输入NaN之一的安静NaN。"
所以两个安静NaN操作数相减的唯一有效结果是一个安静NaN;其他结果无效
C标准说:
(C11, F.9.2表达式转换p1) "[…]
x−x→0。表达式x - x和0。如果x是NaN或infinite"
(此处NaN表示F.2.1p1中的安静NaN;此规范未定义信令NaN的行为。它通常使用术语NaN来表示安静的NaN
既然我看到了质疑英特尔编译器的标准遵从性的答案,而且没有其他人提到过这一点,我将指出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选择default是完全公平的,但我不会把整个Unix战争读回那个决定。
- g++的分段错误(在NaN上使用to_string两次时)
- 输出是NaN,如何
- 为什么我在输出端得到 nan?
- 提升反序列化对象具有 nan 或 -nan 值
- Is !NaN not a NaN?
- NaN 上的宇宙飞船操作员
- C++ STL 排序会检查 NaN 吗?
- C++ 每次运行程序时我都会"nan"输出的问题
- 复制 -nan 表示浮点数,AVX __m256 复制后显示 0
- 如何使用 Node-addon-API 实现 node-nan 回调
- 为什么我的双变量通过添加 c++ 显示 nan?
- nan() 函数的参数
- 为什么 acos() 在使用点积的结果时会导致"nan(ind)"?
- 如何在 c++ 中处理 -nan 输出
- 为什么这段代码返回 -nan(ind)?C++
- Pybind11+nan节点模块冲突
- Nan::ObjectWrap to Napi::Object Wrap 无法访问 JavaScript 中的属性
- 第二个 while 循环未运行,将值设置为 "nan"
- 无穷大与 NAN 值
- 调用某个回调函数两次会导致分段错误:Nan