home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / snip9707.zip / DBL2LONG.C < prev    next >
C/C++ Source or Header  |  1997-07-05  |  2KB  |  90 lines

  1. /* +++Date last modified: 05-Jul-1997 */
  2.  
  3. /*
  4. **  DBL2LONG.C - Functions to round doubles to longs
  5. **  Public domain by Ross G. Cottrell, June 1992
  6. */
  7.  
  8. #include <float.h>
  9. #include <limits.h>
  10. #include "snipmath.h"
  11.  
  12. #if defined(__ZTC__)
  13.  #include <fltenv.h>
  14.  #define SAVEROUND() \
  15.        int fersave = fegetround(); \
  16.        fesetround(FE_TONEAREST)
  17.  #define RESTOREROUND() \
  18.        fesetround(fersave)
  19. #else
  20.  #if !defined(FLT_ROUNDS) || (FLT_ROUNDS != 1)
  21.   #error FLT_ROUNDS needs to be defined to be 1
  22.  #endif
  23.  #define SAVEROUND()
  24.  #define RESTOREROUND()
  25. #endif
  26.  
  27. /* Assume IEEE doubles, little-endian CPU, 32-bit 2's complement longs. */
  28. /* (Actually, the assumptions made here aren't quite that gross.)       */
  29.  
  30. unsigned long dbl2ulong(double t)
  31. {
  32.       SAVEROUND();
  33.       t += 1.0 / DBL_EPSILON;
  34.       RESTOREROUND();
  35.       return *(unsigned long *)&t;
  36. }
  37.  
  38. long dbl2long(double t)
  39. {
  40.       SAVEROUND();
  41.       t += 1.0 / DBL_EPSILON + 2.0 * (LONG_MAX + 1.0);
  42.       RESTOREROUND();
  43.       return *(long *)&t;
  44. }
  45.  
  46. #ifdef TEST
  47.  
  48. #include <stdio.h>
  49. #include <stdlib.h>
  50. #include <math.h>
  51.  
  52. #ifdef __WATCOMC__
  53.  #pragma off (unreferenced);
  54. #endif
  55. #ifdef __TURBOC__
  56.  #pragma argsused
  57. #endif
  58.  
  59. int main(int argc, char **argv)
  60. {
  61.       while (*++argv)
  62.       {
  63.             printf("'%s', as a long: %ld, as an unsigned long: %lu\n",
  64.                   *argv, dbl2long(atof(*argv)), dbl2ulong(atof(*argv)));
  65.       }
  66.       return 0;
  67. }
  68.  
  69. #endif /* TEST */
  70.  
  71. /*
  72.  
  73. EXPLANATION:
  74.  
  75. The offset of 1.0/DBL_EPSILON forces the least significant bit of the
  76. mantissa to represent the integer 1.  This may not work on all formats of
  77. doubles, but I think it's a safe bet for IEEE compliant doubles, and any
  78. other floating point format with a radix of 2.  When this offset is added,
  79. the number should be rounded to the nearest representable value.  If the
  80. compiler does not support extended math funtionality, a compile-time error is
  81. generated if FLT_ROUNDS isn't set to 1, i.e. if not rounding to the nearest
  82. representable value.  The addition of 2.0*(LONG_MAX+1.0) for the signed long
  83. is to prevent the MSB of the mantissa being borrowed for negative inputs - if
  84. this happened, the exponent would change and the LSB of the mantissa would no
  85. longer be worth 1.  This offset would be perfectly okay to use with the
  86. unsigned longs too but it's unnecessary for them, unless you want to get the
  87. answer correct modulo 2^^32 for negatives.
  88.  
  89. */
  90.