home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
MacFormat España 21
/
macformat_21.iso
/
Shareware
/
Programación
/
VideoToolbox
/
VideoToolboxSources
/
IsNan.c
< prev
next >
Wrap
Text File
|
1996-03-07
|
6KB
|
143 lines
/*
IsNan.c
Fast, portable routines to check for IEEE transfinite numbers: INF and NAN. You
should also look at the macro IsFinite() in VideoToolbox.h.
Apple's new header file fp.h defines the macros isfinite(x) and isnan(x), and
the function nan("255"). At present the function nan() is only implemented for
the PowerPC, but presumably Apple will soon extend support to include the 680x0
machines too. Surprisingly, fp.h doesn't include any equivalent to IsInf(). You
could write something like fpclassify(x)==FP_INFINITE, but getting the sign
would take another step.
IsNan and IsInf take a shortcut in distinguishing NaN from INF. The definition
of a NaN in the Apple Numerics book only says that a NaN is distinguished from
an INF by having a nonzero mantissa. Unfortunately, a strict test of this
requires testing the whole mantissa, up to 8 bytes, and in fact the routines in
Plaugher's The Standard C Library do exactly this. (The IEEE standard ought to
have disallowed a NaN code of zero.) We take a hybrid approach, on 680x0
machines (i.e. 10 & 12 byte doubles) my experience is that the NaN code is
always nonzero, unless someone goes out of their way to create a zero-code NaN,
and what's more, in all NaNs the top bit of the mantissa is set. So it is
sufficient to test the top bit and the code byte to distinguish between NaN and INF.
On the other hand, the PowerPC Numerics manual says that the PowerPC chip always
returns a NaN code of zero (seems a foolish choice), so we play safe and test
the whole mantissa when we're dealing with 8 byte doubles.
The Numerical Extensions to C group has proposed in their draft standard that
routines very similar to these become a part of Standard C. Anyone interested in
writing such routines should read: Plauger, P. J. (1992) The Standard C Library.
Englewood Cliffs, NJ: Prentice Hall.
PORTABILITY: Standard C. Should work on Motorola and Intel processors, but has
only been tested on 680x0 and PowerPC processors in Macintosh computers.
HISTORY:
8/24/91 dgp made compatible with THINK C 5.0.
12/23/91 dgp I replaced the #if statements by ordinary if statements, which are
more readable and are allowed to use the sizeof() operator.
Note that most of the if statements will be evaluated and removed by the
compiler, with no runtime penalty.
12/23/91 dgp Wrote my own code to replace the SANE code since it's too slow.
This makes IsNan() about 5 times faster.
My code is based on the Apple Numerics Manual, 2nd edition. It says that
a number is a NAN iff the exponent is all ones and the fraction is nonzero.
I make a slight shortcut in checking only the top 15 bits of the fraction,
since that includes the byte that specifies the NAN type, on the premise
that all NANs that I will actually see in practice will have nonzero type.
My code handles the ordinary cases of 10 or 12 byte doubles. The weird
case of shorter doubles (which are unlikely since they run very slowly)
are detected by the assert() test at the beginning.
12/23/91 dgp Asked the THINK C compiler not to time this routine.
12/29/91 dgp Eliminated the need for SANE.h and Types.h. The SANE stuff
now appears in its own file: SANE.c.
Wrote IsInf().
Wrote a new macro definition, in VideoToolbox.h, for IsFinite(),
that allows fast inline testing for whether a number is ok, i.e. neither
NAN nor INF.
1/14/92 dgp Changed IsNan() to now return the type (1..255) of the NAN, or zero
if not a NAN. This will break programs that assume the true value is always 1,
e.g. nans+=IsNan(a);
Fixed IsInf() to correctly return sign of ±INF.
1/18/92 dgp Rewrote routines, making them simpler, and always checking the most
significant bit of the mantissa in testing for NAN.
6/5/93 dgp Updated documentation.
7/31/94 dgp added support for 8-byte doubles, to support the PowerPC.
*/
#include "VideoToolbox.h"
#if (THINK_C || THINK_CPLUS || SYMANTEC_C)
#pragma options(!profile) /* THINK C: attribute to the caller the time spent here. */
#endif
#define EXPONENT 0
#define MANTISSA ((sizeof(double)-8)/2)
int IsNan(double x);
int IsInf(double x);
#define zeroCode 21 /* NaN with zero code */
int IsNan(double x)
/* Returns x's NAN type (1...255) or zero if x is not a NAN. */
/* If NaN type is zero, return zeroCode. */
{
register short i;
register unsigned long j;
switch(sizeof(double)){
case 8:
j=((unsigned long *)&x)[0];
if((j & 0x7FF00000)==0x7FF00000){ /* either NAN or INF */
j&=0xFFFFF; /* mantissa */
if(j==0 && ((unsigned long *)&x)[1]==0)return 0; /* INF */
i=j>>5;
}else return 0;
break;
case 10:
case 12:
if((((short *)&x)[EXPONENT] & 0x7FFF)==0x7FFF){ /* either NAN or INF */
i=((short *)&x)[MANTISSA] & 0x7FFF;
if(i==0)return 0;
}else return 0;
break;
default:
PrintfExit("%s line %d: Illegal sizeof(double)==%ld\n"
,__FILE__,__LINE__,sizeof(double));
}
i&=0xFF;
if(i==0)i=zeroCode;
return i;
}
int IsInf(double x)
/* Returns -1 for -INF, 0 for not INF, and +1 for +INF. */
{
register short i;
register long j;
switch(sizeof(double)){
case 8:
j=((long *)&x)[0];
if((j & 0x7FF00000)==0x7FF00000){ /* either NAN or INF */
if(j&0xFFFFF==0 && ((long *)&x)[1]==0){
if(j<0)return -1; /* -INF */
else return 1; /* +INF */
}
}
break;
case 10:
case 12:
i=((short *)&x)[EXPONENT];
if((i & 0x7FFF)==0x7FFF){ /* either NAN or INF */
if((((short *)&x)[MANTISSA] & 0x7FFF)==0){
if(i<0)return -1; /* -INF */
else return 1; /* +INF */
}
}
break;
default:
PrintfExit("%s line %d: Illegal sizeof(double)==%ld\n"
,__FILE__,__LINE__,sizeof(double));
}
return 0;
}