s_round.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. #include <limits.h>
  2. #include <math.h>
  3. typedef union
  4. {
  5. struct {
  6. #if defined(__BIG_ENDIAN__)
  7. unsigned long int hi;
  8. unsigned long int lo;
  9. #else
  10. unsigned long int lo;
  11. unsigned long int hi;
  12. #endif
  13. } words;
  14. double dbl;
  15. } DblInHex;
  16. static const unsigned long int signMask = 0x80000000ul;
  17. static const double twoTo52 = 4503599627370496.0;
  18. /*******************************************************************************
  19. * *
  20. * The function round rounds its double argument to integral value *
  21. * according to the "add half to the magnitude and truncate" rounding of *
  22. * Pascal's Round function and FORTRAN's ANINT function and returns the *
  23. * result in double format. This function signals inexact if an ordered *
  24. * return value is not equal to the operand. *
  25. * *
  26. *******************************************************************************/
  27. double round ( double x )
  28. {
  29. DblInHex argument, OldEnvironment;
  30. register double y, z;
  31. register unsigned long int xHead;
  32. register long int target;
  33. argument.dbl = x;
  34. xHead = argument.words.hi & 0x7fffffffUL; // xHead <- high half of |x|
  35. target = ( argument.words.hi < signMask ); // flag positive sign
  36. if ( xHead < 0x43300000ul )
  37. /*******************************************************************************
  38. * Is |x| < 2.0^52? *
  39. *******************************************************************************/
  40. {
  41. if ( xHead < 0x3ff00000ul )
  42. /*******************************************************************************
  43. * Is |x| < 1.0? *
  44. *******************************************************************************/
  45. {
  46. asm ("mffs %0" : "=f" (OldEnvironment.dbl)); // get environment
  47. if ( xHead < 0x3fe00000ul )
  48. /*******************************************************************************
  49. * Is |x| < 0.5? *
  50. *******************************************************************************/
  51. {
  52. if ( ( xHead | argument.words.lo ) != 0ul )
  53. OldEnvironment.words.lo |= 0x02000000ul;
  54. asm ("mtfsf 255,%0" : /*NULLOUT*/ : /*IN*/ "f" ( OldEnvironment.dbl ));
  55. if ( target )
  56. return ( 0.0 );
  57. else
  58. return ( -0.0 );
  59. }
  60. /*******************************************************************************
  61. * Is 0.5 ² |x| < 1.0? *
  62. *******************************************************************************/
  63. OldEnvironment.words.lo |= 0x02000000ul;
  64. asm ("mtfsf 255,%0" : /*NULLOUT*/ : /*IN*/ "f" ( OldEnvironment.dbl ));
  65. if ( target )
  66. return ( 1.0 );
  67. else
  68. return ( -1.0 );
  69. }
  70. /*******************************************************************************
  71. * Is 1.0 < |x| < 2.0^52? *
  72. *******************************************************************************/
  73. if ( target )
  74. { // positive x
  75. y = ( x + twoTo52 ) - twoTo52; // round at binary point
  76. if ( y == x ) // exact case
  77. return ( x );
  78. z = x + 0.5; // inexact case
  79. y = ( z + twoTo52 ) - twoTo52; // round at binary point
  80. if ( y > z )
  81. return ( y - 1.0 );
  82. else
  83. return ( y );
  84. }
  85. /*******************************************************************************
  86. * Is x < 0? *
  87. *******************************************************************************/
  88. else
  89. {
  90. y = ( x - twoTo52 ) + twoTo52; // round at binary point
  91. if ( y == x )
  92. return ( x );
  93. z = x - 0.5;
  94. y = ( z - twoTo52 ) + twoTo52; // round at binary point
  95. if ( y < z )
  96. return ( y + 1.0 );
  97. else
  98. return ( y );
  99. }
  100. }
  101. /*******************************************************************************
  102. * |x| >= 2.0^52 or x is a NaN. *
  103. *******************************************************************************/
  104. return ( x );
  105. }