在C中,您可以使用isnan(x)
测试是否为NaN。然而,许多在线地点,包括例如此SO answer表示您只需使用x!=x
代替。
在任何C规范中都x!=x
作为保证测试x是NaN的方法吗?我自己找不到它,我希望我的代码可以与不同的编译器一起使用。
答案 0 :(得分:9)
NaN作为唯一具有属性x
的值x!=x
是IEEE 754保证。无论是在C中识别NaN
的忠实测试,都可以归结为变量和操作的表示与您打算使用的编译器中的IEEE 754格式和操作的紧密程度。
你应该特别担心“过度精确”以及编译器处理它的方式。当FPU仅方便地支持比编译器想要用于float
和double
类型的更广泛格式的计算时,会发生过多的精度。在这种情况下,计算可以以更宽的精度进行,并且当编译器以不可预测的方式感觉它时,可以四舍五入到类型的精度。
C99标准定义了一种处理这种超额精度的方法,该方法保留了只有NaN与其自身不同的属性,但在1999年之后很长一段时间(甚至现在编译器的作者都不在乎),如果编译器选择舍入计算的超精确结果,那么对于包含计算的有限结果的任何变量x != x
,如果存在精度过高,则x
可能为真。评估第一个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来说不是一个可靠的测试。
答案 1 :(得分:3)
请参阅C标准的Annex F: IEC 60559 floating-point arithmetic规范部分:
F.1简介
定义
26/11/2015
的实现应符合本附件中的规范。未定义
03/12/2015
的实现不需要符合这些规范。
F.9.3关系运算符
如果
__STDC_IEC_559__
是__STDC_IEC_559__
,则表达式x ≠ x
为真。如果
x
是NaN
,则表达式x = x
为false。
F.3运算符和函数
X
中的Nan
宏提供了IEC 60559附录中建议的isnan
功能。