是`x!= x`是一种可以测试NaN的便携方法吗?

在C中,您可以使用isnan(x)测试是否为NaN。 然而,许多地方在线,包括例如这个SO答案说你可以简单地使用x!=x代替。

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

请参考规范部分附录F: C标准的IEC 60559浮点运算 :

F.1简介

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

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

F.9.3关系运算符

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

如果XNan则表达式x = x是假的。

F.3运算符和函数

isnan宏提供了IEC 60559附录中推荐的isnan函数。

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

您应该特别担心“精度过高”以及编译器处理它的方式。 当FPU仅方便地支持比编译器想要用于floatdouble类型的更宽格式的计算时,会发生过多的精度。 在这种情况下,计算可以以更宽的精度进行,并且当编译器以不可预测的方式感觉它时,舍入到类型的精度。

C99标准定义了一种处理这种超出精度的方法,该方法保留了只有NaN与其自身不同的属性,但在1999年之后很长一段时间(甚至现在编译器的作者都不关心),存在过多的精度, x != x如果编译器选择在第一个x和第二个x的求值之间舍入计算的超精度结果,则对于包含计算的有限结果的任何变量xx != x可能为真。

这份报告描述了没有努力实现C99的编译器的黑暗时期(因为它还没有1999年,或者因为他们不够关心)。

这篇2008年的文章描述了GCC如何在2008年开始实施超额精度的C99标准。在此之前,海湾合作委员会可以提供上述报告中描述的所有惊喜。

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