How to generate NaN, -Infinity and +Infinity in ANSI C?
Asked Answered
P

4

50

I use ANSI C89 (not C++), and I want to generate NaN, -Infinity and +Infinity.

Is there any standard way (eg. standard macro)? Or is there any platform and compiler independent way to generate these numbers?

float f = 0.0 / 0.0; // Is f ALWAYS in any platform is NaN?
Physical answered 4/6, 2011 at 9:12 Comment(1)
Arbitrary platforms are not even required by the standard to support NaNs and infinities. I believe an IEEE 754 conformant implementation is required to support obtaining them by division, as in your example, though.Craner
S
45

There is in C99, but not in previous standards AFAIK.

In C99, you'll have NAN and INFINITY macros.

From "Mathematics <math.h>" (§7.12) section

The macro INFINITY expands to a constant expression of type float representing positive or unsigned infinity, if available; ...

If you're stuck with ANSI C89, you're out of luck. See C-FAQ 14.9.

Sheffie answered 4/6, 2011 at 9:19 Comment(3)
You should say "ANSI C89". The current "ANSI C" is C99.Craner
In C89, the macro HUGE_VAL is available to define infinity values.Dirndl
@R..GitHubSTOPHELPINGICE ANSI adopted ISO C99 in 2000. And current C is ISO C18 (or sometimes C17) and ANSI C18, though.Illustrator
L
5

I don't know if this is standard or portable, but here's a start:

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

Strangely enough, I can't get positive NaN using this naive approach.


Also see this: http://www.gnu.org/s/hello/manual/libc/Infinity-and-NaN.html
Lawrencelawrencium answered 4/6, 2011 at 9:19 Comment(5)
funny, that produces inf -inf nan (not -nan) with clang. not really sure what -nan is supposed to mean, actually :-)Sheffie
Result of VS2010: 1.#INF00 -1.#INF00 -1.#IND00Physical
What do 1.#INF00, -1.#IND00 and -1.#IND mean?Haman
@Sheffie Every float has a sign bit, always. You can get positive NaN (or any other number) for float f with f | (1 << 31).Kingwood
To get -NaN, use -(0.f/0.f).Shondrashone
D
2

If you use an old compiler where INFINITY does not exists you can also use the macro HUGE_VAL instead, also defined in the <math.h> library.

HUGE_VAL should be available in C89/C90 standard (ISO/IEC 9899:1990).

References: http://en.cppreference.com/w/c/numeric/math/HUGE_VAL

Dirndl answered 16/4, 2018 at 14:15 Comment(0)
J
2

There is an actual way to create infinity and negative infinity. Based on the IEEE 754 standard, which C89 follows, infinity is defined as a floating point number containing all zeroes in the mantissa (first twenty-three bits), and all ones in the exponent (next eight bits). nan is defined as any number with all ones in the exponent, and anything but all zeroes in the mantissa (because that's infinity). The difficult part is generating this number, but this can be accomplished with the following code:

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;

However, simply casting an unsigned to a float would result in the compiler creating a float of the same value. So, what we have to do is force the compiler to read the memory as a float, which gives us the desired result.

Jansen answered 18/7, 2019 at 20:56 Comment(1)
This breaks strict aliasing. If possible, use memcpy or the traditional divide by zero method instead.Shondrashone

© 2022 - 2024 — McMap. All rights reserved.