[comp.unix.ultrix] Determining IEEE NaN and INF on RISC Ultrix

fkittred@bbn.com (Fletcher Kittredge) (09/21/90)

I need to determine whether a double precision floating point number is
a IEEE NaN or INF (+ or -) value on Sun, HP and DEC RISC systems.  Sun
and HP supply the isnan() and isinf() functions.  I can't find these
functions on the DEC systems.  There is a include file called
/usr/include/nan.h which seems to have macros for determining these
values, but the macros seem to be for a high-endian MIPS system, not
DEC's low-endian version.

Can anyone help me with this?

thanks!
fletcher


Fletcher E. Kittredge  fkittred@bbn.com
Platforms and Tools Group
BBN Software Products Company
10 Fawcett St.
Cambridge, MA. 02138

mark@mips.COM (Mark G. Johnson) (09/22/90)

In article <59582@bbn.BBN.COM> fkittred@spca.bbn.com (Fletcher Kittredge) writes:
 >
 >I need to determine whether a double precision floating point number is
 >a IEEE NaN or INF (+ or -) value on Sun, HP and DEC RISC systems.  Sun


You could resort to coding your own routines.  Just as an simple-simon
demonstration of this possibility, the following hack was thrown together
in 3 minutes.  It was tested on the DECstation 3100 and works under
compiler optimization levels 0, 1, 2, and 3.  These codes are far from
optimum, but they give a flavor of how you might proceed.  Flame if you
must, keeping in mind that the goal below is getting an answer, not efficiency.

The basic ideas are (1) if you compare IEEE NaN with anything, the comparison
fails.  Even a==a fails if a is NaN.  (2) Infinity is what you get when you
overflow a computation.
-----------------------------------------------------------------------------
#include <stdio.h>
#include <math.h>

/* test if argument is IEEE double precision NaN */
int	inn(a)
double	a;
{
	if(a==a) return(0) ;
	else return(1);
}

/* test if argument is IEEE double precision Infinity (+ or -) */
int	iff(b)
double	b;
{
	double	c, d;
	/* laboriously create +Infinity and -Infinity */
	c = 1e10;
	c = (c*c);
	c = (c*c);
	c = (c*c);
	c = (c*c);
	c = (c*c);
	c = (c*c);
	d = -1.0 *c;
	if((b==c) || (b==d)) return(1);
	else return(0);
}



main()
{
	double	x, y, z, q, v ;

	/* set z equal to +Infinity */
	z = 1e10 ;
	z = z*z ;
	z = z*z ;
	z = z*z ;
	z = z*z ;
	z = z*z ;
	z = z*z ;
	z = z*z ;
	z = z*z ;

	/* set y equal to NaN */
	y = z/z ;


	/* set x equal to 1.0 */
	x = 1.0 ;


	printf(" Is %le a NAN?  answer: %d \n", x, inn(x));
	printf(" Is %le a NAN?  answer: %d \n", y, inn(y));
	printf(" Is %le a NAN?  answer: %d \n", z, inn(z));

	printf(" Is %le an infinity?  answer: %d \n", x, iff(x));
	printf(" Is %le an infinity?  answer: %d \n", y, iff(y));
	printf(" Is %le an infinity?  answer: %d \n", z, iff(z));

}
-- 
 -- Mark Johnson	
 	MIPS Computer Systems, 930 E. Arques M/S 2-02, Sunnyvale, CA 94086
	(408) 524-8308    mark@mips.com  {or ...!decwrl!mips!mark}

frank@croton.enet.dec.com (Frank Wortner) (09/24/90)

The ULTRIX 4.0 distribution includes a fixed /usr/include/nan.h file. 
If you can't upgrade,
your could try just reversing the bit fields in the nan.h file.  For
example, in the inf_parts
structure, the fraction_low bit field is the first instead of the last.

Regards,
					Frank

lindahl@violet.berkeley.edu (Ken Lindahl 642-0866) (09/25/90)

In article <59582@bbn.BBN.COM> fkittred@spca.bbn.com (Fletcher Kittredge) writes:
>
>I need to determine whether a double precision floating point number is
>a IEEE NaN or INF (+ or -) value on Sun, HP and DEC RISC systems.  Sun
>and HP supply the isnan() and isinf() functions.  I can't find these
>functions on the DEC systems.  There is a include file called
>/usr/include/nan.h which seems to have macros for determining these
>values, but the macros seem to be for a high-endian MIPS system, not
>DEC's low-endian version.
>
>Can anyone help me with this?
>
>thanks!
>fletcher
>

Under Ultrix V3.1, an alternative is to use either fp_class_f() or
fp_classd(), which are in libc.a (not libm.a!).  The man page for
fp_class_[fd]() is missing from my system (there is a reference to
it at the bottom of the ieee(3m) page), but by trying the obvious,
I've concluded that the syntax is

	int fp_class_f(x)
	float x;

	int fp_class_d(x)
	double x;

The integer values returned are defined in <fp_class.h>.

In another reply, frank@croton.enet.dec.com (Frank Wortner) writes:
>The ULTRIX 4.0 distribution includes a fixed /usr/include/nan.h file. 
>If you can't upgrade,
>your could try just reversing the bit fields in the nan.h file.  For
>example, in the inf_parts
>structure, the fraction_low bit field is the first instead of the last.

I tried this and it works nicely. Thanks, Frank, for the suggestion; I
know it's obvious, but I must confess that I hadn't thought of it.
The IsINF(), IsPosNAN(), and IsNegNAN() macros should only be used
after IsNANorINF() has already tested TRUE -- otherwise, these three
macros could return TRUE for some non-exceptional values.

Finally, here's an observation and a possible bug: the log() function
in libm.a handles exceptions differently than the log() function
in libm43.a. Specifically,

			libm.a			libm43.a
			--------------          ---------
log(0)			= NaN (negative)	= -Infinity
log(Infinity)		= NaN (negative)	= Infinity

I don't know which of these behaviors is consistent with IEEE 754
(I haven't actually read it), but the libm43.a version seems more
useful to me. Beyond that, the math(3m) man page seems to imply that
libm.a and libm43.a should be comparable except perhaps for speed and
very small differences in returned values. This is not true for the 
the two versions of log(). Comments, anyone? By the way, I have not
performed any kind of exhaustive search for discrencies between libm.a
and libm43.a; I just stumbled across this one.


Ken Lindahl				lindahl@violet.berkeley.edu
Advanced Technology Planning,
Information Systems and Technology
University of California at Berkeley