s_trunc.c 3.0 KB

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