如何在ANSI C中生成NaN、-Infinity和+Infinity?

50

我使用的是 ANSI C89(不是 C++),我想生成 NaN-Infinity+Infinity

是否有任何标准方法(例如标准宏)? 或者是否有任何平台和编译器无关的方法来生成这些数字?

float f = 0.0 / 0.0; // Is f ALWAYS in any platform is NaN?

1
标准甚至不要求任意平台支持NaN和无穷大。我相信符合IEEE 754的实现需要支持通过除法获得它们,就像您的示例一样。 - R.. GitHub STOP HELPING ICE
4个回答

44

据我所知,C99中有此功能,而在之前的标准中则没有。

在C99中,您将拥有NANINFINITY宏。

来自“数学<math.h>(§7.12)部分

如果可用,宏INFINITY扩展为类型为float的常量表达式,表示正无穷大或无符号无穷大...

如果您使用的是ANSI C89,则没有此选项。请参见C-FAQ 14.9


21
你应该说"ANSI C89"。现在的"ANSI C"是C99。 - R.. GitHub STOP HELPING ICE
2
在C89中,宏HUGE_VAL可用于定义无穷大的值。 - mlel
ANSI在2000年采用了ISO C99标准。目前的C语言是ISO C18(有时也称为C17)和ANSI C18。 - FrankHB

5
我���知道这是否是标准的或可移植的,但以下是一个开端:
jcomeau@intrepid:/tmp$ cat test.c; make test; ./test
#include <stdio.h>
int main() {
 printf("%f\n", 1.0 / 0);
 printf("%f\n", -1.0 / 0);
 printf("%f\n", 0.0 / 0);
 return 0;
}
cc     test.c   -o test
test.c: In function ‘main’:
test.c:3: warning: division by zero
test.c:4: warning: division by zero
test.c:5: warning: division by zero
inf
-inf
-nan

奇怪的是,我用这种天真的方法无法得到正向NaN。


另请参见:http://www.gnu.org/s/hello/manual/libc/Infinity-and-NaN.html


3
有趣的是,使用clang时会产生“inf -inf nan”(而不是“-nan”)。实际上我不太确定“-nan”应该是什么意思 :-) - Mat
VS2010的结果: 1.#INF00 -1.#INF00 -1.#IND00 - Amir Saniyan
1
1.#INF00、-1.#IND00和-1.#IND是什么意思? - phuclv
1
@Mat 每个浮点数都有一个符号位,始终如此。你可以使用 f | (1 << 31) 得到 float 类型的正无穷(或任何其他数字)。 - Nearoo
使用 -(0.f/0.f) 可以获取 -NaN - S.S. Anne

2

2
有一种实际的方法可以创建正无穷和负无穷。根据C89遵循的IEEE 754标准,正无穷被定义为一个浮点数,其中尾数(前23位)包含所有零,指数(接下来的8位)包含所有1。nan被定义为任何指数全部为1,且尾数不全为0的数字(因为那是正无穷)。难点在于生成这个数字,但可以通过以下代码完成:
unsigned int p = 0x7F800000; // 0xFF << 23
unsigned int n = 0xFF800000; // 0xFF8 << 20
unsigned int pnan = 0x7F800001; // or anything above this up to 0x7FFFFFFF
unsigned int nnan = 0xFF800001; // or anything above this up to 0xFFFFFFFF

float positiveInfinity = *(float *)&p;
float negativeInfinity = *(float *)&n;
float positiveNaN = *(float *)&pnan;
float negativeNaN = *(float *)&nnan;

然而,仅仅将一个 "unsigned" 转换为 "float",会导致编译器创建一个相同值的 "float"。因此,我们需要强制编译器将内存读取为 "float",这样就得到了我们想要的结果。

1
这会破坏严格别名规则。如果可能的话,请改用memcpy或传统的除零方法。 - S.S. Anne

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接