如果 x != x 给出相同的结果,为什么 isnan(x) 存在?

Why does isnan(x) exist if x != x gives the same result?

众所周知,对于任何浮点类型的变量 x != x iff(当且仅当)xNaN(非数字)。或者相反的版本:x == x 当且仅当 x 不是 NaN。那么如果使用语言的自然能力可以获得相同的结果,为什么 WG14 决定定义 isnan(x) (math.h) 呢?动机是什么?更好的代码可读性?

附加问题:isnan(x)x != x在功能上有区别吗?

if the same result can be obtained using natural capabilities of the language?

C 没有指定 x == x 当且仅当 x 不是 NaN. Many implementations do that though. C does not require adherence to IEEE_754isnan(x) 定义明确。

对可移植代码使用 isnan(x)


C in 类型的表示(自 C99 起)有

Two values (other than NaNs) with the same object representation compare equal, but values that compare equal may have different object representations.

...但这并没有指定比较 2 个 NAN 的行为。


__STDC_IEC_559__(类似于遵守 IEEE-754)定义为 1(C 不需要的东西)时,则

“如果 x 是 NaN,则表达式 x != x 为真。”

“如果 x 是 NaN,则表达式 x == x 为假。”

__STDC_IEC_559__ 未定义为 1 时,请谨慎假设浮点数学边缘的行为,例如 NAN 相等。


[编辑以解决一些评论]

C,在 FP 数学的角落,缺乏 IEEE-754 的细节。正如对 IEEE-754 的引用所证明的那样,C89 允许 NAN,但缺少 isnan(x)。没有“具有相同对象表示的两个值(NaN 除外)比较相等,...”来指导。当时,没有指定 NAN 的 x==x。在 C99 中,isnan(x) 不是破坏或使先前的代码无效,而是被定义为明确的 NAN 测试。正如我所见,x==x 对于 NAN 仍未指定,但它通常会导致 falseisnan(x) 还提供代码清晰度。关于 C 和 NAN 的很多内容是 fuzzy:往返 有效载荷序列 信号 encoding/discernment、NAN 可用性,...


Are there any functional differences between isnan(x) and x != x?

除了上面讨论的 isnan(x)x != x 的定义明确的功能外,还有一些晦涩的功能:

  • isnan(x) 计算 x 一次,而 x != x 计算两次。如果 x 是像 y++.

    这样的表达式,就会有所不同
  • isnan(x)sematic 类型进行操作。当“实现支持评估类型但不支持语义类型的 NaN”时,这会有所不同。 x != x 对评估类型进行操作。研究 FLT_EVAL_METHOD 了解更多详情。

Why isnan(x) exists if x != x (or x == x) gives the same result?

因为他们并不总是给出相同的结果。

例如GCC当compiling with -funsafe-math-optimizations替换

x - x

0.0

so ( x == x ) 即使 xNaN.

也可以为真

-funsafe-math-optimizations is also enabled if either -fast-math or -Ofast is specified:

...

-ffast-math

Sets the options -fno-math-errno, -funsafe-math-optimizations, -ffinite-math-only, -fno-rounding-math, -fno-signaling-nans, -fcx-limited-range and -fexcess-precision=fast.

This option causes the preprocessor macro __FAST_MATH__ to be defined.

This option is not turned on by any -O option besides -Ofast since it can result in incorrect output for programs that depend on an exact implementation of IEEE or ISO rules/specifications for math functions. It may, however, yield faster code for programs that do not require the guarantees of these specifications.

...

-funsafe-math-optimizations

Allow optimizations for floating-point arithmetic that (a) assume that arguments and results are valid and (b) may violate IEEE or ANSI standards. When used at link time, it may include libraries or startup files that change the default FPU control word or other similar optimizations.

This option is not turned on by any -O option since it can result in incorrect output for programs that depend on an exact implementation of IEEE or ISO rules/specifications for math functions. It may, however, yield faster code for programs that do not require the guarantees of these specifications. Enables -fno-signed-zeros, -fno-trapping-math, -fassociative-math and -freciprocal-math.

...

所以在某些情况下,您可能出于性能原因想要使用浮点优化,但仍需要检查 NaN,唯一的方法是明确检查 [=36] =].

此外,C standard states in 6.2.6.1p4:

Two values (other than NaNs) with the same object representation compare equal

实现所需的功能需要能够以某种方式检查 NaN,而不是比较对象表示(位)。因此 isnan() 功能是实现“如果 xNaNx == x 为假”的先决条件。

必须有某种类型的功能来检查 NaN 独立于 x == x 否则它只是一个无法实现的无限递归定义。

如果您需要做的只是检查 NaN 并且不需要浪费 CPU 个周期来实际进行比较,那么可以在 isnan() 之类的东西中公开该功能性能优势。