`x!=x` 是测试 NaN 的可移植方法吗?

Posted

技术标签:

【中文标题】`x!=x` 是测试 NaN 的可移植方法吗?【英文标题】:Is `x!=x` a portable way to test for NaN? 【发布时间】:2016-02-28 17:40:24 【问题描述】:

在 C 语言中,您可以使用 isnan(x) 测试是否为双精度值。但是网上很多地方,例如这个SO answer 说你可以简单地使用x!=x 来代替。

在任何 C 规范中,x!=x 是保证测试 x 是否为 NaN 的方法吗?我自己找不到它,我希望我的代码可以与不同的编译器一起使用。

【问题讨论】:

你还在努力寻找优化isnan()的方法吗?您是否真的对您的应用程序进行了基准测试并发现这是瓶颈? 【参考方案1】:

NaN 作为唯一值 x 和属性 x!=x 是 IEEE 754 保证。在 C 中识别 NaN 是否是一个忠实的测试,归结为变量的表示和操作在您打算使用的编译器中映射到 IEEE 754 格式和操作的紧密程度。

您应该特别担心“超精度”以及编译器处理它的方式。当 FPU 仅方便地支持比编译器希望用于 floatdouble 类型的更广泛格式的计算时,会发生超精度。在这种情况下,可以以更广泛的精度进行计算,并在编译器以不可预知的方式感觉时四舍五入到类型的精度。

C99 标准定义了一种处理这种过度精度的方法,该方法保留了只有 NaN 与自身不同的属性,但在 1999 年之后的很长一段时间内(甚至现在编译器的作者都不关心),存在过度精度如果编译器选择在计算第一个 x 和第二个x

report 描述了编译器的黑暗时期,他们没有努力实现 C99(可能是因为当时还不是 1999 年,或者是因为他们不够关心)。

2008 post 描述了 GCC 如何在 2008 年开始实施 C99 标准以实现超精度。在此之前,GCC 可以提供上述报告中描述的所有惊喜。

当然,如果目标平台根本没有实现 IEEE 754,那么 NaN 值甚至可能不存在,或者存在并且具有与 IEEE 754 指定的属性不同的属性。常见的情况是编译器非常忠实地实现了 IEEE 754将 FLT_EVAL_METHOD 设置为 0、1 或 2(所有这些都保证 x != x iff x 是 NaN),或具有超精度的非标准实现的编译器,其中 x != x 不是对 NaN 的可靠测试.

【讨论】:

我认为你的最后一点是关键。 x != x 适用于 IEEE 754 浮点,但 IEEE 754 不是强制性的。甚至NaN 本身的存在也无法保证。 isnan(x) 是否真的准确地告诉您,xx != x 不能用于相同目的的那些平台上是否为 NaN?我想象一个编译器生成两个不同的代码来计算x;一个用于isnan(x) 调用,一个用于您在该条件内使用它的任何内容。 换句话说,是否有一个程序使用以下函数f 导致f 在使用这样的编译器构建然后运行时打印出“0 is NaN”? void f(double x) if (x != x) printf("%f is NaN\n"); 【参考方案2】:

请参考C标准的规范部分Annex F: IEC 60559 floating-point arithmetic:

F.1 简介

定义__STDC_IEC_559__ 的实现应符合本附件中的规范。

未定义 __STDC_IEC_559__ 的实现不需要符合这些规范。

F.9.3 关系运算符

如果xNaN,则表达式x ≠ x 为真。

如果XNan,则表达式x = x 为假。

F.3 运算符和函数

<math.h> 中的 isnan 宏提供了 IEC 60559 附录中推荐的 isnan 函数。

【讨论】:

实现是否真的定义了__STDC_IEC_559__,还是像C++ 版本一样,编译器不想声称兼容? @Adam,有效的问题! gcc 5.2.1 20151028 确实定义了它,clang 3.5.2-3 没有。对于 x86_64-pc-linux-gnu 目标,即。 @Adam 根据我的经验,C 编译器可能会通过定义他们在实践中不尊重的符号来声明,例如 clang -std=c99 -mno-sse2 声称 FLT_EVAL_METHOD 是零,但实际上它不是这样计算的.我没想到检查它是否定义了__STDC_IEC_559__:***.com/questions/17663780/…

以上是关于`x!=x` 是测试 NaN 的可移植方法吗?的主要内容,如果未能解决你的问题,请参考以下文章

在 C++ 中实现无操作语句的可移植方式是啥?

负 NaN 不是 NaN?

你如何在 JavaScript 中测试 NaN?

用于 Fortran 的 mex 网关中 REAL 变量的可移植声明

XHR的可移植sendAsBinary

matlab:如果 x > 1 则可以产生 NaN 的快速函数