当前位置: 首页 > 知识库问答 >
问题:

为什么NaN-NaN==0.0与英特尔C编译器?

洪高阳
2023-03-14

众所周知,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

2015年MSVC奥运会产生了类似的东西。然而,英特尔C 15生产:

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

具体来说,秦纳 - 秦纳 = 0.0

这...不可能是对的,对吧?相关标准(ISO C,ISO C,IEEE 754)对此有什么说法,为什么编译器之间的行为会有差异?

共有3个答案

澹台硕
2023-03-14

由于我看到了一个指责英特尔编译器符合标准的答案,而且没有其他人提到过这一点,所以我要指出,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战争重新解读为那个决定。

董法
2023-03-14

这……不可能是对的,对吗?我的问题:相关标准(ISO C、ISO C、IEEE 754)对此有何说明?

彼得·阿卜杜林已经回答了为什么编译器给出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或无穷大,则0不等价”

(此处NaN表示符合F.2.1p1的安静NaN。本规范未定义发信号通知NaN的行为。它通常使用术语NaN来表示安静的NaN”)

钱均
2023-03-14

Intel C编译器中的默认浮点处理是/fp: Fast,它不安全地处理NaN(例如,这也导致NaN==NaNtrue)。尝试指定/fp:严格/fp:精确,看看是否有帮助。

 类似资料:
  • 问题内容: 为什么返回 Javascript? 在文档页面上,我看到以下内容: ## 针对NaN的测试 相等运算符(和)不能用于测试的值。使用代替。 有没有参考资料可以回答这个问题?不客气。 问题答案: 严格的回答 :因为JS规范是这样说的: 如果Type(x)是Number,则 如果x为NaN,则返回false。 如果y为NaN,则返回false。 有用的答案 :浮点数的IEEE 754规范(所

  • 我很熟悉在JavaScript中是“怪异的”,即总是返回,如本文所述。因此,不应进行比较来检查,而应使用isNaN(..)取而代之的是。 所以我惊讶地发现 这似乎不一致。为什么会有这种行为? 它是怎么工作的?方法是否专门检查?

  • 问题内容: 只是出于好奇。 数字似乎不太合逻辑。顺便说一句,就像或返回假。这是javascript的特性之一,还是有原因呢? 编辑:谢谢你的回答。但是,要让所有人适应现实并非易事。阅读答案和Wiki我了解得更多,但仍然有类似 与NaN的比较始终会返回无序结果,即使与自身进行比较也是如此。比较谓词是信令或非信令,信令版本表示此类比较的无效异常。相等和不相等谓词是无信号的,因此x = x返回false

  • 我的问题很简单,我知道我遗漏了一些非常明显的东西,我就是不知道它是什么。。。。 我对霍尔特·温特斯的测试预测结果是南,我不知道为什么。有人能帮忙吗? 我正在使用Jupyter笔记本电脑,并试图使用霍尔特-温特斯方法预测一个SKU的销售额。我甚至用了 以下是我使用的代码: 有人能指出我可能遗漏了什么吗?这似乎是一个简单的问题和一个简单的解决方案,但它踢我的屁股。 谢谢

  • 问题内容: 从我读到的内容来看,它用于修复CPU中的错误,而无需修改BIOS。根据我对汇编的基本知识,我知道汇编指令在内部由CPU分解为微代码,并相应地执行。但是intel以某种方式可以在系统启动和运行时进行一些更新。 有人有更多信息吗?是否有关于微码可以做什么以及如何使用的文档? 编辑:我读过维基百科的文章:没弄清楚我怎么能自己写一些,以及它有什么用。 问题答案: 在较早的时期,微代码在CPU中

  • 本文向大家介绍请解释下NaN表示什么呢?typeof NaN结果是什么?相关面试题,主要包含被问及请解释下NaN表示什么呢?typeof NaN结果是什么?时的应答技巧和注意事项,需要的朋友参考一下 点击查看MDN对NaN的解释说明 判断一个值是否是NaN 等号运算符(== 和 ===) 不能被用来判断一个值是否是 NaN。必须使用 Number.isNaN() 或 isNaN() 函数。在执行自