fmod.c 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. /* origin: FreeBSD /usr/src/lib/msun/src/e_fmod.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. /*
  13. * fmod(x,y)
  14. * Return x mod y in exact arithmetic
  15. * Method: shift and subtract
  16. */
  17. #include "libm.h"
  18. static const double Zero[] = {0.0, -0.0,};
  19. double fmod(double x, double y)
  20. {
  21. int32_t n,hx,hy,hz,ix,iy,sx,i;
  22. uint32_t lx,ly,lz;
  23. EXTRACT_WORDS(hx, lx, x);
  24. EXTRACT_WORDS(hy, ly, y);
  25. sx = hx & 0x80000000; /* sign of x */
  26. hx ^= sx; /* |x| */
  27. hy &= 0x7fffffff; /* |y| */
  28. /* purge off exception values */
  29. if ((hy|ly) == 0 || hx >= 0x7ff00000 || /* y=0,or x not finite */
  30. (hy|((ly|-ly)>>31)) > 0x7ff00000) /* or y is NaN */
  31. return (x*y)/(x*y);
  32. if (hx <= hy) {
  33. if (hx < hy || lx < ly) /* |x| < |y| */
  34. return x;
  35. if (lx == ly) /* |x| = |y|, return x*0 */
  36. return Zero[(uint32_t)sx>>31];
  37. }
  38. /* determine ix = ilogb(x) */
  39. if (hx < 0x00100000) { /* subnormal x */
  40. if (hx == 0) {
  41. for (ix = -1043, i = lx; i > 0; i <<= 1)
  42. ix -= 1;
  43. } else {
  44. for (ix = -1022, i = hx<<11; i > 0; i <<= 1)
  45. ix -= 1;
  46. }
  47. } else
  48. ix = (hx>>20) - 1023;
  49. /* determine iy = ilogb(y) */
  50. if (hy < 0x00100000) { /* subnormal y */
  51. if (hy == 0) {
  52. for (iy = -1043, i = ly; i > 0; i <<= 1)
  53. iy -= 1;
  54. } else {
  55. for (iy = -1022, i = hy<<11; i > 0; i <<= 1)
  56. iy -= 1;
  57. }
  58. } else
  59. iy = (hy>>20) - 1023;
  60. /* set up {hx,lx}, {hy,ly} and align y to x */
  61. if (ix >= -1022)
  62. hx = 0x00100000|(0x000fffff&hx);
  63. else { /* subnormal x, shift x to normal */
  64. n = -1022-ix;
  65. if (n <= 31) {
  66. hx = (hx<<n)|(lx>>(32-n));
  67. lx <<= n;
  68. } else {
  69. hx = lx<<(n-32);
  70. lx = 0;
  71. }
  72. }
  73. if(iy >= -1022)
  74. hy = 0x00100000|(0x000fffff&hy);
  75. else { /* subnormal y, shift y to normal */
  76. n = -1022-iy;
  77. if (n <= 31) {
  78. hy = (hy<<n)|(ly>>(32-n));
  79. ly <<= n;
  80. } else {
  81. hy = ly<<(n-32);
  82. ly = 0;
  83. }
  84. }
  85. /* fix point fmod */
  86. n = ix - iy;
  87. while (n--) {
  88. hz = hx-hy;
  89. lz = lx-ly;
  90. if (lx < ly)
  91. hz -= 1;
  92. if (hz < 0) {
  93. hx = hx+hx+(lx>>31);
  94. lx = lx+lx;
  95. } else {
  96. if ((hz|lz) == 0) /* return sign(x)*0 */
  97. return Zero[(uint32_t)sx>>31];
  98. hx = hz+hz+(lz>>31);
  99. lx = lz+lz;
  100. }
  101. }
  102. hz = hx-hy;
  103. lz = lx-ly;
  104. if (lx < ly)
  105. hz -= 1;
  106. if (hz >= 0) {
  107. hx = hz;
  108. lx = lz;
  109. }
  110. /* convert back to floating value and restore the sign */
  111. if ((hx|lx) == 0) /* return sign(x)*0 */
  112. return Zero[(uint32_t)sx>>31];
  113. while (hx < 0x00100000) { /* normalize x */
  114. hx = hx+hx+(lx>>31);
  115. lx = lx+lx;
  116. iy -= 1;
  117. }
  118. if (iy >= -1022) { /* normalize output */
  119. hx = ((hx-0x00100000)|((iy+1023)<<20));
  120. INSERT_WORDS(x, hx|sx, lx);
  121. } else { /* subnormal output */
  122. n = -1022 - iy;
  123. if (n <= 20) {
  124. lx = (lx>>n)|((uint32_t)hx<<(32-n));
  125. hx >>= n;
  126. } else if (n <= 31) {
  127. lx = (hx<<(32-n))|(lx>>n);
  128. hx = sx;
  129. } else {
  130. lx = hx>>(n-32); hx = sx;
  131. }
  132. INSERT_WORDS(x, hx|sx, lx);
  133. }
  134. return x; /* exact output */
  135. }