【问题标题】:Why does GCC yield -nan and clang and intel yield +nan for 0.0/0.0?为什么 GCC 为 0.0/0.0 产生 -nan 和 clang 和 intel 产生 +nan?
【发布时间】:2015-11-20 03:59:37
【问题描述】:

当我调试代码时,我发现 GCC 和 Clang 都为 0.0/0.0 生成 nan,这是我所期望的,但 GCC 生成的 nan 将符号位设置为 1,而 Clang 将其设置为 0(在与 ICC 达成协议,如果我没记错的话)。

现在显然这两种形式都是允许的,但我一直想知道为什么0.0/0.0 会使 GCC 输出“否定”结果(打印它会给出-nan),而-(0.0/0.0) 会给出“肯定”结果?更令人困惑的是,-0.0/0.0 又是“否定”了。这是一个不断折叠的怪癖吗?

编辑

实际上,正是不断的折叠使它成为一个积极的 nan。如果我在运行时强制计算,我会在 GCC 和 Clang 上得到负 nan

volatile float zero = 0.0;
std::cout << (zero/zero); // -nan

有人可以解释一下吗? x86 FPU 上的符号位是否设置为 1?

【问题讨论】:

    标签: c++ gcc nan ieee-754


    【解决方案1】:

    IEEE-754 没有指定 NaN 的符号:

    当输入或结果为 NaN 时,此标准不 解释 NaN 的符号。但是请注意,对位的操作 字符串 - 复制、取反、abs、copySign — 指定 NaN 结果的符号位,有时基于 NaN 操作数的符号位。这 逻辑谓词 totalOrder 也受 a 的符号位的影响 NaN 操作数。对于所有其他操作,本标准未规定 NaN 结果的符号位,即使只有一个输入 NaN, 或者当 NaN 是由无效操作产生时。

    现在让我们看看Intel 64 and IA-32 Architectures Software Developer’s Manual Volume 1: Basic Architecture

    其中,英特尔在这种情况下确实指定了一个特定的 NaN 值,称为QNaN Floating-Point Indefinite(参见表 4-1),它在 #IA(无效算术异常)时返回(参见表 8-10 )。 寻找 0 除以 0。

    您会看到,对于该值,符号位已设置。

    【讨论】:

    • 啊,我明白了。因此,clang 和 icc 似乎会产生不一致的结果,具体取决于您是直接计算 0/0 还是启用优化。这是故意的吗?
    • 不确定你的意思。编译器可以对符号位做任何事情。 IEEE 标准中未指定符号位。在这里使用 +NaN 或 -NaN 是编译器的好权利。但是,x86 Intel CPU 总是会产生一个带有负号位的 NaN,根据标准,这也是有效的。有些编译器可能知道硬件行为,有些不知道,有些可能不关心。如果你好奇,clang 的源代码是 llvm/lib/Support/APFloat.cpp,divideSpecial 方法。我真的懒得钻研 gcc 源码^^
    • 仅供参考,ARM VFP 将产生积极的信号,它不像硬件制造商之间达成一致。
    猜你喜欢
    • 2021-05-23
    • 2015-12-02
    • 2017-03-28
    • 2019-08-04
    • 1970-01-01
    • 2021-12-12
    • 2017-11-26
    相关资源
    最近更新 更多