s_trunc.c 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  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 trunc truncates its double argument to integral value *
  22. * and returns the result in double format. This function signals *
  23. * inexact if an ordered return value is not equal to the operand. *
  24. * *
  25. *******************************************************************************/
  26. double trunc ( double x )
  27. {
  28. DblInHex argument,OldEnvironment;
  29. register double y;
  30. register unsigned long int xhi;
  31. register long int target;
  32. argument.dbl = x;
  33. xhi = argument.words.hi & 0x7fffffffUL; // xhi <- high half of |x|
  34. target = ( argument.words.hi < signMask ); // flag positive sign
  35. if ( xhi < 0x43300000ul )
  36. /*******************************************************************************
  37. * Is |x| < 2.0^53? *
  38. *******************************************************************************/
  39. {
  40. if ( xhi < 0x3ff00000ul )
  41. /*******************************************************************************
  42. * Is |x| < 1.0? *
  43. *******************************************************************************/
  44. {
  45. if ( ( xhi | argument.words.lo ) != 0ul )
  46. { // raise deserved INEXACT
  47. asm ("mffs %0" : "=f" (OldEnvironment.dbl));
  48. OldEnvironment.words.lo |= 0x02000000ul;
  49. asm ("mtfsf 255,%0" : /*NULLOUT*/ : /*IN*/ "f" ( OldEnvironment.dbl ));
  50. }
  51. if ( target ) // return properly signed zero
  52. return ( 0.0 );
  53. else
  54. return ( -0.0 );
  55. }
  56. /*******************************************************************************
  57. * Is 1.0 < |x| < 2.0^52? *
  58. *******************************************************************************/
  59. if ( target )
  60. {
  61. y = ( x + twoTo52 ) - twoTo52; // round at binary point
  62. if ( y > x )
  63. return ( y - 1.0 );
  64. else
  65. return ( y );
  66. }
  67. else
  68. {
  69. y = ( x - twoTo52 ) + twoTo52; // round at binary point.
  70. if ( y < x )
  71. return ( y + 1.0 );
  72. else
  73. return ( y );
  74. }
  75. }
  76. /*******************************************************************************
  77. * Is |x| >= 2.0^52 or x is a NaN. *
  78. *******************************************************************************/
  79. return ( x );
  80. }