在GCC内置描述中,它说:
GCC 提供内置版本的 ISO C99 浮点比较宏,以避免引发无序操作数的异常。它们与标准宏具有相同的名称(isgreater、isgreaterequal、isless、islessequal、islessgreater 和 isunordered),并带有 _builtin 前缀。我们希望库实现者能够简单地将每个标准宏#define 为其内置等效宏。以同样的方式,GCC 提供了 fpclassify、isfinite、isinf_sign、isnormal 和 signbit 内置函数,并以 _builtin 为前缀。 isinf 和 isnan 内置函数在带或不带 _builtin 前缀时都会出现。
所以,我不太能够解析这个。浮点比较什么时候应该引发异常? C 标准强制要求他们这样做吗?强制他们不这样做?没有强制要求什么吗?并且 -
__builtin_isnan()
的作用与 isnan()
不同吗?
这里的例外情况是,GCC 文档指的是 IEEE 754 浮点例外。如果你做类似的事情
a < b
并且其中一个操作数是 NaN,将引发 FP 异常(无效)。这意味着 FPU 中的某个位将保持设置状态,直到被程序员明确清除为止。通过使用
isgreater
/isless
/等。程序员可以避免触发 FP 异常。
GCC 的标准库函数的内置函数主要用于优化,当某些参数或环境约束可以在编译时已知时。
__builtin_isnan()
以类似的方式工作。
__builtin_isnan()
的主要目的是在禁用信号NaN支持时允许将isnan(x)
优化为(x != x)
(即-fno-signaling-nans
,这是默认值)。
isnan(x)
和(x != x)
的行为并不相同。差异在于评估信号 NaN 时。
(以上是问题的主要回答,以下是更多技术细节。)
IEEE 754(标准)定义了“安静”NaN 和“信号”NaN,彻底了解它们可能会让您头疼。 (我是认真的。)
如果您不熟悉 IEEE 浮点及其比较操作,这里有一些基础知识:
!(x > y)
不等于浮点数中的 (x <= y)
。“安静”和“信号”术语是相对的,我将它们添加到引号中,因为“安静”比较并不总是安静,而“信号”并不总是发出信号。
IEEE 754 中的“安静”比较映射到 C 中的这些:
(x==y)
、isgreater
、isgreaterequal
、isless
、islessequal
、isunordered
。
IEEE 754 中的“信号”比较映射到 C 中的这些:
iseqsig
、(x>y)
、(x>=y)
、(x<y)
和 (x<=y)
。 isunordered
没有“信号”变体,因为这没有意义。
对于“安静”比较,它们不会用安静的 NaN 操作数引发 FP 异常。 但是 当任何操作数是信号 NaN 时,它们确实会抛出“无效操作”(FE_INVALID) 异常。
对于“信号”比较,当任何操作数为 NaN 时,无论其信号位如何,它们都会引发异常。 (也就是说,它们也会对安静的 NaN 抛出异常。)
还有一些函数永远不会抛出异常,即使存在信号 NaN。
fpclassify
函数,包括isnan
,都是这样的。 (这些也是 IEEE 754 中的标准操作,尽管不同的语言为这些操作提供了不同的 API。)
在这个关于 isnan() 和 (x!=x) 的 Stack Overflow 答案中我做了一个快速比较表:
| isnan(x) | (x != x) | (x >= x) | isgreaterequal(x,x)
--------------+----------+-----------+------------+--------------------
-Wfloat-equal | no warn | warn | no warn | no warn
--------------+----------+-----------+------------+--------------------
Finite number | false | false | true | true
Infinity | false | false | true | true
NaN (quiet) | true | true | FPE; false | false
SNaN | true | FPE; true | FPE; false | FPE; false
因此您可以了解
isnan
、!=
、>=
和 isgreaterequal
在不同类型的浮点值上的表现。