人们如何在 C89 中检查 nan 和 inf

huk*_*ing 6 c floating-point c99 nan c89

isnan(), isinf() 直到 C99 才出现在规范中,无论如何在 C89 中实现这样的功能?

我可以if (d * 0 != 0)用来检查 d 是 NaN 还是 Inf,但我们总是使用选项编译我们的项目,该选项-Werror=float-equal想大喊:error: no == or != on float point value

那么人们如何在 C89 中检查 nan 和 inf 呢?

chu*_*ica 6

自 C99

isinf(x)isnan(x)处理 的实浮点类型x和 对于其他类型(如 )未定义intisinf(x)并且isnan(x)是宏。

isinf(x)isnan(x)使用相同的名称float, double, long double,因此就像一个重载的函数。

信息

对于 C89,我们可以使用单独的函数来测试_MAX. 请注意,C89 没有定义long double.

“自己动手”isinf()可以使用以下内容。

#include <float.h>
int isinf_f(float x) { return x < -FLT_MAX || x > FLT_MAX; }
int isinf_d(double x) { return x < -DBL_MAX || x > DBL_MAX; }
Run Code Online (Sandbox Code Playgroud)

请注意,C 不要求实现支持无穷大。如果是这样,上述内容永远不会正确。

伊斯南

C89 的“自己动手”isnan()更棘手。可以在下面作为函数或简单的宏来完成。功能依赖于现代的 Not-a-number 行为,其中 Nan 永远不等于任何东西,甚至不等于它本身。将是通过C89规定,但一般底层浮点系统遵循这一点。否则,您需要更特定于平台的方法。

/* Note `x` used twice here - so use with caution */
#define my_is_nan(x) ( (x) != (x) )

int isnan_f(float x) { x != x; }
int isnan_d(double x) { x != x; }
Run Code Online (Sandbox Code Playgroud)

请注意,C 不要求实现支持Not-a-number。如果是这样,上述内容永远不会正确。

鉴于 C89 狂野西部时代,我不会假设符合 IEEE 754。 InfinityNAN正是缺乏正式合规性的任何浮点实现的边缘。祝你好运。


C 允许使用更广泛的 FP 数学,具体取决于FLT_EVAL_METHOD因此1.0f / 7.0f可能使用double. 这使事情有点复杂,但使用真正的函数确实将x表达式强制转换为所需的类型。


Adr*_*ica 2

如果您的系统使用IEEE 754 标准来表示浮点值(大多数系统都是这样做的),那么您可以显式检查NaNinf值。单精度(32 位)浮点值具有1 符号位(位 31)、8 bit 指数(位 30-23)和23 bit 尾数(位 22-0),布局如下(二进制格式):

SEEEEEEEEMMMMMMMMMMMMMMMMMMMMMMM
Run Code Online (Sandbox Code Playgroud)

无穷大值用全 1 的指数和全 0 的尾数表示(符号位区分负无穷大和正无穷大)。

NaN值由全 1 和非零分数的指数表示(安静的 NaN具有最高有效的尾数位设置,而信号 Nan则清除该位)。

因此,通过“转换”float为无符号 32 位整数,我们可以显式检查这些表示形式(假设unsigned int是 32 位类型):

SEEEEEEEEMMMMMMMMMMMMMMMMMMMMMMM
Run Code Online (Sandbox Code Playgroud)

双精度值的表示类似,但具有11指数位 (62-52) 和52尾数位 (51-0)。

  • `unsigned int mask = *(unsigned int *)(&amp;test);` 违反了严格别名,[忽略任何潜在的字节序问题](https://en.wikipedia.org/wiki/Endianness#Floating-point_and_endianness),并假设所有“float”的位完全适合“unsigned int”。 (11认同)