home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Mac Game Programming Gurus / TricksOfTheMacGameProgrammingGurus.iso / More Source / Libraries / VideoToolbox 95.04.18 / VideoToolboxSources / IsNan.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-11-15  |  5.5 KB  |  142 lines  |  [TEXT/MMCC]

  1. /* IsNan.c
  2. Fast, portable routines to check for IEEE transfinite numbers: INF and NAN. You
  3. should also look at the macro IsFinite() in VideoToolbox.h.
  4.  
  5. Apple's new header file fp.h defines the macros isfinite(x) and isnan(x), and
  6. the function nan("255"). At present the function nan() is only implemented for
  7. the PowerPC, but presumably Apple will soon extend support to include the 680x0
  8. machines too. Surprisingly, fp.h doesn't include any equivalent to IsInf(). You
  9. could write something like fpclassify(x)==FP_INFINITE, but getting the sign
  10. would take another step.
  11.  
  12. IsNan and IsInf take a shortcut in distinguishing NaN from INF. The definition
  13. of a NaN in the Apple Numerics book only says that a NaN is distinguished from
  14. an INF by having a nonzero mantissa. Unfortunately, a strict test of this
  15. requires testing the whole mantissa, up to 8 bytes, and in fact the routines in
  16. Plaugher's The Standard C Library do exactly this. (The IEEE standard ought to
  17. have disallowed a NaN code of zero.) We take a hybrid approach, on 680x0
  18. machines (i.e. 10 & 12 byte doubles) my experience is that the NaN code is
  19. always nonzero, unless someone goes out of their way to create a zero-code NaN,
  20. and what's more, in all NaNs the top bit of the mantissa is set. So it is
  21. sufficient to test the top bit and the code byte to distinguish between NaN and INF.
  22. On the other hand, the PowerPC Numerics manual says that the PowerPC chip always
  23. returns a NaN code of zero (seems a foolish choice), so we play safe and test
  24. the whole mantissa when we're dealing with 8 byte doubles.
  25.  
  26. The Numerical Extensions to C group has proposed in their draft standard that
  27. routines very similar to these become a part of Standard C. Anyone interested in
  28. writing such routines should read: Plauger, P. J. (1992) The Standard C Library.
  29. Englewood Cliffs, NJ: Prentice Hall.
  30.  
  31. PORTABILITY: Standard C. Should work on Motorola and Intel processors, but has
  32. only been tested on 680x0 and PowerPC processors in Macintosh computers.
  33.  
  34. HISTORY:
  35. 8/24/91 dgp    made compatible with THINK C 5.0.
  36. 12/23/91 dgp I replaced the #if statements by ordinary if statements, which are 
  37.     more readable and are allowed to use the sizeof() operator.
  38.     Note that most of the if statements will be evaluated and removed by the
  39.     compiler, with no runtime penalty.
  40. 12/23/91 dgp Wrote my own code to replace the SANE code since it's too slow.
  41.     This makes IsNan() about 5 times faster.
  42.     My code is based on the Apple Numerics Manual, 2nd edition. It says that
  43.     a number is a NAN iff the exponent is all ones and the fraction is nonzero.
  44.     I make a slight shortcut in checking only the top 15 bits of the fraction,
  45.     since that includes the byte that specifies the NAN type, on the premise
  46.     that all NANs that I will actually see in practice will have nonzero type.
  47.     My code handles the ordinary cases of 10 or 12 byte doubles. The weird
  48.     case of shorter doubles (which are unlikely since they run very slowly)
  49.     are detected by the assert() test at the beginning.
  50. 12/23/91 dgp Asked the THINK C compiler not to time this routine.
  51. 12/29/91 dgp Eliminated the need for SANE.h and Types.h. The SANE stuff
  52.     now appears in its own file: SANE.c. 
  53.     Wrote IsInf().
  54.     Wrote a new macro definition, in VideoToolbox.h, for IsFinite(), 
  55.     that allows fast inline testing for whether a number is ok, i.e. neither 
  56.     NAN nor INF. 
  57. 1/14/92    dgp    Changed IsNan() to now return the type (1..255) of the NAN, or zero
  58.     if not a NAN. This will break programs that assume the true value is always 1,
  59.     e.g. nans+=IsNan(a);
  60.     Fixed IsInf() to correctly return sign of ±INF.
  61. 1/18/92    dgp    Rewrote routines, making them simpler, and always checking the most 
  62.     significant bit of the mantissa in testing for NAN.
  63. 6/5/93    dgp    Updated documentation.
  64. 7/31/94 dgp added support for 8-byte doubles, to support the PowerPC.
  65. */
  66.  
  67. #include "VideoToolbox.h"
  68. #include <assert.h>
  69. #if (THINK_C || THINK_CPLUS)
  70.     #pragma options(!profile)    /* THINK C: attribute to the caller the time spent here. */
  71. #endif
  72. #define EXPONENT 0
  73. #define MANTISSA ((sizeof(double)-8)/2)
  74. int IsNan(double x);
  75. int IsInf(double x);
  76. #define zeroCode 21    // NaN with zero code
  77.  
  78. int IsNan(double x)
  79. /* Returns x's NAN type (1...255) or zero if x is not a NAN. */
  80. /* If NaN type is zero, return zeroCode. */
  81. {
  82.     register short i;
  83.     register unsigned long j;
  84.  
  85.     switch(sizeof(double)){
  86.     case 8:
  87.         j=((unsigned long *)&x)[0];
  88.         if((j & 0x7FF00000)==0x7FF00000){        /* either NAN or INF */
  89.             j&=0xFFFFF;                            /* mantissa */
  90.             if(j==0 && ((unsigned long *)&x)[1]==0)return 0;    /* INF */
  91.             i=j>>5;
  92.         }else return 0;
  93.         break;
  94.     case 10:
  95.     case 12:
  96.         if((((short *)&x)[EXPONENT] & 0x7FFF)==0x7FFF){        /* either NAN or INF */
  97.             i=((short *)&x)[MANTISSA] & 0x7FFF;
  98.             if(i==0)return 0;
  99.         }else return 0;
  100.         break;
  101.     default:
  102.         PrintfExit("%s line %d: Illegal sizeof(double)==%ld\n"
  103.             ,__FILE__,__LINE__,sizeof(double));
  104.     }
  105.     i&=0xFF;
  106.     if(i==0)i=zeroCode;
  107.     return i;
  108. }
  109.  
  110. int IsInf(double x)
  111. /* Returns -1 for -INF, 0 for not INF, and +1 for +INF. */
  112. {
  113.     register short i;
  114.     register long j;
  115.  
  116.     switch(sizeof(double)){
  117.     case 8:
  118.         j=((long *)&x)[0];
  119.         if((j & 0x7FF00000)==0x7FF00000){                    /* either NAN or INF */
  120.             if(j&0xFFFFF==0 && ((long *)&x)[1]==0){
  121.                 if(j<0)return -1;                            /*  -INF */
  122.                 else return 1;                                /*  +INF */
  123.             }
  124.         }
  125.         break;
  126.     case 10:
  127.     case 12:
  128.         i=((short *)&x)[EXPONENT];
  129.         if((i & 0x7FFF)==0x7FFF){                            /*  either NAN or INF */
  130.             if((((short *)&x)[MANTISSA] & 0x7FFF)==0){
  131.                 if(i<0)return -1;                            /*  -INF */
  132.                 else return 1;                                /*  +INF */
  133.             }
  134.         }
  135.         break;
  136.     default:
  137.         PrintfExit("%s line %d: Illegal sizeof(double)==%ld\n"
  138.             ,__FILE__,__LINE__,sizeof(double));
  139.     }
  140.     return 0;
  141. }
  142.