fmodq.c 3.5 KB

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