How to use nan and inf in C?
Asked Answered
A

10

117

I have a numerical method that could return nan or inf if there was an error, and for testing purposed I'd like to temporarily force it to return nan or inf to ensure the situation is being handled correctly. Is there a reliable, compiler-independent way to create values of nan and inf in C?

After googling for about 10 minutes I've only been able to find compiler dependent solutions.

Amide answered 17/12, 2009 at 18:57 Comment(1)
floats are not defined by the C standard. So there is no compiler-independent way of doing what you want.Seventh
L
115

You can test if your implementation has it:

#include <math.h>
#ifdef NAN
/* NAN is supported */
#endif
#ifdef INFINITY
/* INFINITY is supported */
#endif

The existence of INFINITY is guaranteed by C99 (or the latest draft at least), and "expands to a constant expression of type float representing positive or unsigned infinity, if available; else to a positive constant of type float that overflows at translation time."

NAN may or may not be defined, and "is defined if and only if the implementation supports quiet NaNs for the float type. It expands to a constant expression of type float representing a quiet NaN."

Note that if you're comparing floating point values, and do:

a = NAN;

even then,

a == NAN;

is false. One way to check for NaN would be:

#include <math.h>
if (isnan(a)) { ... }

You can also do: a != a to test if a is NaN.

There is also isfinite(), isinf(), isnormal(), and signbit() macros in math.h in C99.

C99 also has nan functions:

#include <math.h>
double nan(const char *tagp);
float nanf(const char *tagp);
long double nanl(const char *tagp);

(Reference: n1256).

Docs INFINITY Docs NAN

Lewie answered 17/12, 2009 at 19:15 Comment(7)
Excellent answer. Reference for the NAN and INFINITY macros is C99 §7.12 paragraphs 4 and 5. Besides (isnan(a)) you can also check for NaN using (a != a) on a conforming implementation of C.Melise
For the love of readability, a != a should NEVER be used.Kobayashi
@ChrisKerekes: sadly, some of us have NAN but not isnan(). Yes, this is 2017. :(Calamitous
C does not require, when a is a not-a-number, for a == NAN to return false. IEEE requires it. Even implementations that adhere to IEEE, do so mostly. When isnan() not implemented, still better to wrap the test than directly code a == NAN.Spinnaker
To add to what chux said, even on an IEEE 754 system with the same compiler, a != a may behave differently with two different optimization levels. Use this comparison with caution!Inflammable
Thanks @WillEccles, I didn't know about that!Lewie
I really should have noted that [on every compiler I have used] you have to specify this behavior--on GCC, this would be done with -ffast-math, which allows GCC to deviate from the standard to emit faster math (which may change the behavior of such a comparison). I don't think -O3 or similar would ever cause this to happen.Inflammable
A
34

There is no compiler independent way of doing this, as neither the C (nor the C++) standards say that the floating point math types must support NAN or INF.

Edit: I just checked the wording of the C++ standard, and it says that these functions (members of the templated class numeric_limits):

quiet_NaN() 
signalling_NaN()

wiill return NAN representations "if available". It doesn't expand on what "if available" means, but presumably something like "if the implementation's FP rep supports them". Similarly, there is a function:

infinity() 

which returns a positive INF rep "if available".

These are both defined in the <limits> header - I would guess that the C standard has something similar (probably also "if available") but I don't have a copy of the current C99 standard.

Allx answered 17/12, 2009 at 19:0 Comment(6)
That's disappointing and surprising. Don't C and C++ conform to the IEEE floating point numbers, which have a standard representation for nan and inf?Amide
In C99, the C header <math.h> defines nan(), nanf(), and nanl() that return different representations of NaN (as a double, float, and int respectively), and infinity (if avaliable) could be returned by generating one with log(0) or something. There's no standard way to check for them, even in C99. The <float.h> header (<limits.h> is for integral types) is unfortunately silent about inf and nan values.Orth
Wow, that's a big mixup. nanl() returns a long double, not an int like my comment says. I don't know why I didn't realize that when I was typing it.Orth
@Chris, see my answer for C99.Lewie
@ChrisLutz Those definitions are not in VC++ 2012's math.h. But there are some in limits.h, see msdn.microsoft.com/en-us/library/6hthw3cb(v=vs.110).aspx . Example is float n = numeric_limits<float>::infinity();Vulgarian
@IngeHenriksen - Pretty sure Microsoft has stated that it has no intention of VC++ supporting C99.Orth
M
33

This works for both float and double:

double NAN = 0.0/0.0;
double POS_INF = 1.0 /0.0;
double NEG_INF = -1.0/0.0;

Edit: As someone already said, the old IEEE standard said that such values should raise traps. But the new compilers almost always switch the traps off and return the given values because trapping interferes with error handling.

Makepeace answered 17/12, 2009 at 19:26 Comment(6)
Trapping was one option for error handling allowed under 754-1985. The behavior used by most modern hardware/compilers was also allowed (and was the preferred behavior for many of the members of the committee). Many implementers incorrectly assumed that trapping was required due to the unfortunate use of the term "exceptions" in the standard. This has been greatly clarified in the revised 754-2008.Melise
Hi, Stephen, you're right, but the standard also says: "A user should be able to request a trap on any of the five exceptions by specifying a handler for it. He should be able to request that an existing handler be disabled, saved, or restored. He should also be able to determine whether a specific trap handler for a designated exception has been enabled." "should" as defined (2. Definitions) means "strongly recommended" and its implementation should only be left out if the architecture etc. makes it impractical. 80x86 fully supports the standard, so there's no reason for C not to support it.Makepeace
I agree that C should require 754 (2008) floating point, but there are good reasons for it not to; specifically, C is used in all kinds of environments that other than x86 -- including embedded devices that don't have hardware floating-point, and signal processing devices where programmers don't even want to use floating point. Rightly or wrongly, those uses account for a lot of inertia in the language spec.Melise
I don't know why the top answer made it up there. It doesn't give any way to produce the requested values. This answer does.Moiety
#define is_nan(x) ((x) != (x)) may be useful as a simple, portable test for NAN.Poyang
It is not a compiler who switches the traps, but the programmer. I heavily use the FPE traps to debug my numerical code, and just had a library that used a similar recipe. As a result I could not use the FPE trap, and wasted an hour to catch an error that could be caught in five minutes if the programmers of the library bothered to use NAN macro...Potentilla
D
24
double a_nan = strtod("NaN", NULL);
double a_inf = strtod("Inf", NULL);
Doodlesack answered 1/8, 2014 at 13:7 Comment(3)
This is a smart portable solution! C99 requires strtod and does convert NaN's and Inf's.Photoelectric
Not that there's a drawback with this solution; they are not constants. You cannot use these values to initialize a global variable for instance (or to initialize an array).Autocade
@Marc. You can always have an initializer function that calls these once and sets them in the global namespace. It's a very workable drawback.Scot
G
20

A compiler independent way, but not processor independent way to get these:

int inf = 0x7F800000;
return *(float*)&inf;

int nan = 0x7F800001;
return *(float*)&nan;

This should work on any processor which uses the IEEE 754 floating point format (which x86 does).

UPDATE: Tested and updated.

Giltedged answered 17/12, 2009 at 19:8 Comment(14)
This is, unfortunately, won't port between 32/64 bit computers. Preprocessor conditionals for platform would be needed This is a bit hacky, but is better than no solution, of course.Maldon
@WaffleMatt - why wouldn't this port between 32/64 bit? IEEE 754 single-precision float is 32-bit regardless of the addressing size of the underlying processor.Giltedged
Casting to (float &) ? That doesn't look like C to me. You need int i = 0x7F800000; return *(float *)&i;Orth
@Chris Lutz - yes, I just noticed that too (fixed).Giltedged
Won't 1/0 trigger an exception/signal under some conditions? I know there's a Win32 "SEH" exception called "Integer Divide by Zero".Muscadine
!/0 leads to undefined behaviour land for all C implementations.Allx
@Tim Sylvester - You are correct. 1/0 triggers a signal. Updated answer to use bits in both cases (and fix incorrect bit format of nan - which was actually inf).Giltedged
What about platforms with 16 bit ints?Seventh
@kotlinski - correct. This requires a machine with 32-bit ints.Giltedged
There's a positive and negative infinity. Change to 0xFF8... for negative infinity. As said in another comment, the new compilers should all return values because compiler builders really hate IEEE 754 requirements of signal handling. The NaN will be a qNaN in this case.Makepeace
Note that 0x7f800001 is a so-called signaling NaN in the IEEE-754 standard. Although most libraries and hardware don't support signaling NaNs, it is likely better to return a quiet NaN like 0x7fc00000.Melise
Warning: this may trigger Undefined Behavior through violation of strict aliasing rules. The recommended (and best supported in compilers) way to do type punning is through union members.Photoelectric
Maybe use int32_t instead of int, if possible, for future compatibility?Busiek
In addition to the strict aliasing issue that @Photoelectric pointed out, this assumes that the target uses the same endian for integers as floating point, which definitely isn't always the case.Chequerboard
R
3
<inf.h>

/* IEEE positive infinity.  */

#if __GNUC_PREREQ(3,3)
# define INFINITY   (__builtin_inff())
#else
# define INFINITY   HUGE_VALF
#endif

and

<bits/nan.h>
#ifndef _MATH_H
# error "Never use <bits/nan.h> directly; include <math.h> instead."
#endif


/* IEEE Not A Number.  */

#if __GNUC_PREREQ(3,3)

# define NAN    (__builtin_nanf (""))

#elif defined __GNUC__

# define NAN \
  (__extension__                                  \
   ((union { unsigned __l __attribute__ ((__mode__ (__SI__))); float __d; })  \
    { __l: 0x7fc00000UL }).__d)

#else

# include <endian.h>

# if __BYTE_ORDER == __BIG_ENDIAN
#  define __nan_bytes       { 0x7f, 0xc0, 0, 0 }
# endif
# if __BYTE_ORDER == __LITTLE_ENDIAN
#  define __nan_bytes       { 0, 0, 0xc0, 0x7f }
# endif

static union { unsigned char __c[4]; float __d; } __nan_union
    __attribute_used__ = { __nan_bytes };
# define NAN    (__nan_union.__d)

#endif  /* GCC.  */
Rafe answered 4/3, 2013 at 0:14 Comment(0)
L
0

Here is a simple way to define those constants, and I'm pretty sure it's portable:

const double inf = 1.0/0.0;
const double nan = 0.0/0.0;

When I run this code:

printf("inf  = %f\n", inf);
printf("-inf = %f\n", -inf);
printf("nan  = %f\n", nan);
printf("-nan = %f\n", -nan);

I get:

inf  = inf
-inf = -inf
nan  = -nan
-nan = nan
Lapstrake answered 25/2, 2020 at 18:4 Comment(1)
I looked in /usr/include/math.h to see what they do. They use built-in values if available, but if not it looks like they use: code INFINITY = HUGE_VALF = 1e10000f code NAN = (0.0f / 0.0f) In any case it looks like INFINITY and NAN are defined as solid constants.Lapstrake
F
0

In MSVC, the following is defined in correct_math.h, which is included in math.h:

#ifndef _HUGE_ENUF
    #define _HUGE_ENUF  1e+300  // _HUGE_ENUF*_HUGE_ENUF must overflow
#endif

#define INFINITY   ((float)(_HUGE_ENUF * _HUGE_ENUF))
#define HUGE_VAL   ((double)INFINITY)
#define HUGE_VALF  ((float)INFINITY)
#define HUGE_VALL  ((long double)INFINITY)
#ifndef _UCRT_NEGATIVE_NAN
// This operation creates a negative NAN adding a - to make it positive
#define NAN        (-(float)(INFINITY * 0.0F))
#else
// Keep this for backwards compatibility
#define NAN        ((float)(INFINITY * 0.0F))
#endif
Fayth answered 14/2, 2023 at 10:2 Comment(1)
This does not really answer the question. If you have a different question, you can ask it by clicking Ask Question. To get notified when this question gets new answers, you can follow this question. Once you have enough reputation, you can also add a bounty to draw more attention to this question. - From ReviewElysha
C
-1

I usually use

#define INFINITY (1e999)

or

const double INFINITY = 1e999

which works at least in IEEE 754 contexts because the highest representable double value is roughly 1e308. 1e309 would work just as well, as would 1e99999, but three nines is sufficient and memorable. Since this is either a double literal (in the #define case) or an actual Inf value, it will remain infinite even if you're using 128-bit (“long double”) floats.

Cobb answered 15/7, 2014 at 22:58 Comment(4)
This is very dangerous, in my opinion. Imagine how someone migrates your code to 128 bit floats in 20 or so years (after your code goes through an unbelievably complex evolution, none of the stages of which you were able to predict today). Suddenly, the exponent range drastically increases, and all your 1e999 literals no longer round to +Infinity. Per Murphy's laws, this breaks an algorithm. Worse: a human programmer doing the "128-bit" build will not likely spot that error in advance. I.e. most likely it will be too late when this error is found and recognized. Very dangerous.Photoelectric
Of course, the worst case scenario above might be far from realistic. But still, consider the alternatives! It's better to stay on the safe side.Photoelectric
"In 20 years", heh. Come on. This answer is not that bad.Marti
@Photoelectric I don't like this either, but really?Longwise
R
-2

I'm also surprised these aren't compile time constants. But I suppose you could create these values easily enough by simply executing an instruction that returns such an invalid result. Dividing by 0, log of 0, tan of 90, that kinda thing.

Radmilla answered 17/12, 2009 at 19:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.