tags:

views:

1046

answers:

5

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 complier dependent solutions.

+11  A: 

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.

anon
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?
Graphics Noob
C doesn't mandate IEEE floating-point representations.
Steve Emmerson
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.
Chris Lutz
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.
Chris Lutz
@Chris, see my answer for C99.
Alok
+6  A: 

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.

Aaron
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.
McPherrinM
@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.
Aaron
Casting to `(float return *(float *)`
Chris Lutz
@Chris Lutz - yes, I just noticed that too (fixed).
Aaron
Won't `1/0` trigger an exception/signal under some conditions? I know there's a Win32 "SEH" exception called "Integer Divide by Zero".
Tim Sylvester
!/0 leads to undefined behaviour land for all C implementations.
anon
@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).
Aaron
What about platforms with 16 bit ints?
kotlinski
@kotlinski - correct. This requires a machine with 32-bit ints.
Aaron
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.
Thorsten S.
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`.
Stephen Canon
A: 

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.

Carl Smotricz
+9  A: 

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(ocnst char *tagp);

(Reference: n1256).

Alok
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.
Stephen Canon
Thanks Stephen, updated.
Alok
+3  A: 

This functions in 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.

Thorsten S.
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.
Stephen Canon
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.
Thorsten S.
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.
Stephen Canon