NaN and Inf

Introduction

NaN is an acronym for Not a Number and Inf is of course an abbreviation of infinity.

Some standard (I think the IEEE Standard for Binary Floating-Point Arithmetic, Std 754-1985, ANSI) defines both of these. You can test to see if you have one or the other by using the macros int isnan(double) and int isinf(double) in the standard C library.

They are soo cute and fluffy...Where Can I Get One?

Well a number of functions in the maths library can produce them such as sqrt(3) and log(3) I beleive. A quick way to get them would be:


	#include <ieeefp.h>

	double NaN, Inf;
	fp_except_t old_mask;

	/* unset the "Floating Point eXception Divide by Zero" bit in the fp
	 * exception mask. Save the old mask (so we can restore it when we have
	 * finished in old_mask. */
	old_mask = fpsetmask(~FP_X_DZ);

	/* I don't understand the question and it seems neither does the FPU */
	NaN = 0 / 0;
	/* There are of course an infinite number of 0s in any whole number */
	Inf = 1 / 0;

	/* tell the FPU to forget the occurence of any DivZ exceptions that have
	 * occured. If we didn't do this then next time an FP exception occured
	 * we might get signalled with the wrong type as the DivZ bit is still
	 * set.
	 *
	 * We cast the return value to void to let the compiler (and readers of
	 * our code) know we are deliberatley ignoring fpresetsticky's return
	 * value and haven't just forgotten. */
	(void)fpresetsticky(FP_X_DZ);

	/* restore the fp exception mask. Any future DivZ's will cause a SIGFPE
	 * to be delivered. Mmmm...can't wait! */
	(void)fpsetmask(old_mask);

What Are All These fp functions?

They make up part of the IEEE floating point API. Floating point maths is an awful hack (not that I can think of anything better) so there are a lot of options you can tweak.

The problem started with maths...how many numbers (fractions allowed) between 0 and 1? How many bits are required to store all those numbers? So what do you do is you only have {8, 16, 32, 64, 128} bits? You approximate...

The IEEE API (usually defined in ieeefp.h) allows you to control which way numbers are rounded (to the nearest representable number, up, down or just truncate), set the precision FP maths is done with (within limits) and control what happens on an FP exception (divide by zero, overflow, loss of precision etc).

Ordinarily when you divide by 0 your process recevies SIGFPE (which, by default, causes your program to exit). As you saw above you can use fpsetmask to disable that. It's then up to you to use fpgetsticky to test for such errors. You can use a similar method to test for overflow which is handy when reading a FP number from an untrusted source.

The FP exceptions you can look at (how many of these work might depend on your hardware and/or OS - these are from FreeBSD) are:

Exception (of type fp_except_t)Description
FP_X_INVInvalid FP operation
FP_X_DNMLDenormalised - not sure how this can occur
FP_X_DZDivide by Zero
FP_X_OFLOperation caused an overflow
FP_X_UFLOperation caused an underflow
FP_X_IMPOperation caused a loss of precision (caused IMPrecision)
FP_X_STKStack fault - not sure about this...perhaps the FP functions use a stack in their calculations...