s_round.c 5.1 KB

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