e_fmodl.c 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. /* @(#)e_fmod.c 5.1 93/09/24 */
  2. /*
  3. * ====================================================
  4. * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
  5. *
  6. * Developed at SunPro, 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. * fmodl(x,y)
  14. * Return x mod y in exact arithmetic
  15. * Method: shift and subtract
  16. */
  17. #include <openlibm_math.h>
  18. #include "math_private.h"
  19. static const long double one = 1.0, Zero[] = {0.0, -0.0,};
  20. long double
  21. fmodl(long double x, long double y)
  22. {
  23. int64_t n,hx,hy,hz,ix,iy,sx,i;
  24. u_int64_t lx,ly,lz;
  25. GET_LDOUBLE_WORDS64(hx,lx,x);
  26. GET_LDOUBLE_WORDS64(hy,ly,y);
  27. sx = hx&0x8000000000000000ULL; /* sign of x */
  28. hx ^=sx; /* |x| */
  29. hy &= 0x7fffffffffffffffLL; /* |y| */
  30. /* purge off exception values */
  31. if((hy|ly)==0||(hx>=0x7fff000000000000LL)|| /* y=0,or x not finite */
  32. ((hy|((ly|-ly)>>63))>0x7fff000000000000LL)) /* or y is NaN */
  33. return (x*y)/(x*y);
  34. if(hx<=hy) {
  35. if((hx<hy)||(lx<ly)) return x; /* |x|<|y| return x */
  36. if(lx==ly)
  37. return Zero[(u_int64_t)sx>>63]; /* |x|=|y| return x*0*/
  38. }
  39. /* determine ix = ilogb(x) */
  40. if(hx<0x0001000000000000LL) { /* subnormal x */
  41. if(hx==0) {
  42. for (ix = -16431, i=lx; i>0; i<<=1) ix -=1;
  43. } else {
  44. for (ix = -16382, i=hx<<15; i>0; i<<=1) ix -=1;
  45. }
  46. } else ix = (hx>>48)-0x3fff;
  47. /* determine iy = ilogb(y) */
  48. if(hy<0x0001000000000000LL) { /* subnormal y */
  49. if(hy==0) {
  50. for (iy = -16431, i=ly; i>0; i<<=1) iy -=1;
  51. } else {
  52. for (iy = -16382, i=hy<<15; i>0; i<<=1) iy -=1;
  53. }
  54. } else iy = (hy>>48)-0x3fff;
  55. /* set up {hx,lx}, {hy,ly} and align y to x */
  56. if(ix >= -16382)
  57. hx = 0x0001000000000000LL|(0x0000ffffffffffffLL&hx);
  58. else { /* subnormal x, shift x to normal */
  59. n = -16382-ix;
  60. if(n<=63) {
  61. hx = (hx<<n)|(lx>>(64-n));
  62. lx <<= n;
  63. } else {
  64. hx = lx<<(n-64);
  65. lx = 0;
  66. }
  67. }
  68. if(iy >= -16382)
  69. hy = 0x0001000000000000LL|(0x0000ffffffffffffLL&hy);
  70. else { /* subnormal y, shift y to normal */
  71. n = -16382-iy;
  72. if(n<=63) {
  73. hy = (hy<<n)|(ly>>(64-n));
  74. ly <<= n;
  75. } else {
  76. hy = ly<<(n-64);
  77. ly = 0;
  78. }
  79. }
  80. /* fix point fmod */
  81. n = ix - iy;
  82. while(n--) {
  83. hz=hx-hy;lz=lx-ly; if(lx<ly) hz -= 1;
  84. if(hz<0){hx = hx+hx+(lx>>63); lx = lx+lx;}
  85. else {
  86. if((hz|lz)==0) /* return sign(x)*0 */
  87. return Zero[(u_int64_t)sx>>63];
  88. hx = hz+hz+(lz>>63); lx = lz+lz;
  89. }
  90. }
  91. hz=hx-hy;lz=lx-ly; if(lx<ly) hz -= 1;
  92. if(hz>=0) {hx=hz;lx=lz;}
  93. /* convert back to floating value and restore the sign */
  94. if((hx|lx)==0) /* return sign(x)*0 */
  95. return Zero[(u_int64_t)sx>>63];
  96. while(hx<0x0001000000000000LL) { /* normalize x */
  97. hx = hx+hx+(lx>>63); lx = lx+lx;
  98. iy -= 1;
  99. }
  100. if(iy>= -16382) { /* normalize output */
  101. hx = ((hx-0x0001000000000000LL)|((iy+16383)<<48));
  102. SET_LDOUBLE_WORDS64(x,hx|sx,lx);
  103. } else { /* subnormal output */
  104. n = -16382 - iy;
  105. if(n<=48) {
  106. lx = (lx>>n)|((u_int64_t)hx<<(64-n));
  107. hx >>= n;
  108. } else if (n<=63) {
  109. lx = (hx<<(64-n))|(lx>>n); hx = sx;
  110. } else {
  111. lx = hx>>(n-64); hx = sx;
  112. }
  113. SET_LDOUBLE_WORDS64(x,hx|sx,lx);
  114. x *= one; /* create necessary signal */
  115. }
  116. return x; /* exact output */
  117. }