remainder.c 1.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
  1. /* origin: FreeBSD /usr/src/lib/msun/src/e_remainder.c */
  2. /*
  3. * ====================================================
  4. * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
  5. *
  6. * Developed at SunSoft, a Sun Microsystems, Inc. business.
  7. * Permission to use, copy, modify, and distribute this
  8. * software is freely granted, provided that this notice
  9. * is preserved.
  10. * ====================================================
  11. */
  12. /* remainder(x,p)
  13. * Return :
  14. * returns x REM p = x - [x/p]*p as if in infinite
  15. * precise arithmetic, where [x/p] is the (infinite bit)
  16. * integer nearest x/p (in half way case choose the even one).
  17. * Method :
  18. * Based on fmod() return x-[x/p]chopped*p exactlp.
  19. */
  20. #include "libm.h"
  21. double remainder(double x, double p)
  22. {
  23. int32_t hx,hp;
  24. uint32_t sx,lx,lp;
  25. double p_half;
  26. EXTRACT_WORDS(hx, lx, x);
  27. EXTRACT_WORDS(hp, lp, p);
  28. sx = hx & 0x80000000;
  29. hp &= 0x7fffffff;
  30. hx &= 0x7fffffff;
  31. /* purge off exception values */
  32. if ((hp|lp) == 0 || /* p = 0 */
  33. hx >= 0x7ff00000 || /* x not finite */
  34. (hp >= 0x7ff00000 && (hp-0x7ff00000 | lp) != 0)) /* p is NaN */
  35. return (x*p)/(x*p);
  36. if (hp <= 0x7fdfffff)
  37. x = fmod(x, p+p); /* now x < 2p */
  38. if (((hx-hp)|(lx-lp)) == 0)
  39. return 0.0*x;
  40. x = fabs(x);
  41. p = fabs(p);
  42. if (hp < 0x00200000) {
  43. if (x + x > p) {
  44. x -= p;
  45. if (x + x >= p)
  46. x -= p;
  47. }
  48. } else {
  49. p_half = 0.5*p;
  50. if (x > p_half) {
  51. x -= p;
  52. if (x >= p_half)
  53. x -= p;
  54. }
  55. }
  56. GET_HIGH_WORD(hx, x);
  57. if ((hx&0x7fffffff) == 0)
  58. hx = 0;
  59. SET_HIGH_WORD(x, hx^sx);
  60. return x;
  61. }