remquo.c 1.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. #include <math.h>
  2. #include <stdint.h>
  3. double remquo(double x, double y, int *quo)
  4. {
  5. union {double f; uint64_t i;} ux = {x}, uy = {y};
  6. int ex = ux.i>>52 & 0x7ff;
  7. int ey = uy.i>>52 & 0x7ff;
  8. int sx = ux.i>>63;
  9. int sy = uy.i>>63;
  10. uint32_t q;
  11. uint64_t i;
  12. uint64_t uxi = ux.i;
  13. *quo = 0;
  14. if (uy.i<<1 == 0 || isnan(y) || ex == 0x7ff)
  15. return (x*y)/(x*y);
  16. if (ux.i<<1 == 0)
  17. return x;
  18. /* normalize x and y */
  19. if (!ex) {
  20. for (i = uxi<<12; i>>63 == 0; ex--, i <<= 1);
  21. uxi <<= -ex + 1;
  22. } else {
  23. uxi &= -1ULL >> 12;
  24. uxi |= 1ULL << 52;
  25. }
  26. if (!ey) {
  27. for (i = uy.i<<12; i>>63 == 0; ey--, i <<= 1);
  28. uy.i <<= -ey + 1;
  29. } else {
  30. uy.i &= -1ULL >> 12;
  31. uy.i |= 1ULL << 52;
  32. }
  33. q = 0;
  34. if (ex < ey) {
  35. if (ex+1 == ey)
  36. goto end;
  37. return x;
  38. }
  39. /* x mod y */
  40. for (; ex > ey; ex--) {
  41. i = uxi - uy.i;
  42. if (i >> 63 == 0) {
  43. uxi = i;
  44. q++;
  45. }
  46. uxi <<= 1;
  47. q <<= 1;
  48. }
  49. i = uxi - uy.i;
  50. if (i >> 63 == 0) {
  51. uxi = i;
  52. q++;
  53. }
  54. if (uxi == 0)
  55. ex = -60;
  56. else
  57. for (; uxi>>52 == 0; uxi <<= 1, ex--);
  58. end:
  59. /* scale result and decide between |x| and |x|-|y| */
  60. if (ex > 0) {
  61. uxi -= 1ULL << 52;
  62. uxi |= (uint64_t)ex << 52;
  63. } else {
  64. uxi >>= -ex + 1;
  65. }
  66. ux.i = uxi;
  67. x = ux.f;
  68. if (sy)
  69. y = -y;
  70. if (ex == ey || (ex+1 == ey && (2*x > y || (2*x == y && q%2)))) {
  71. x -= y;
  72. q++;
  73. }
  74. q &= 0x7fffffff;
  75. *quo = sx^sy ? -(int)q : (int)q;
  76. return sx ? -x : x;
  77. }