1*37da2899SCharles.Forsyth /* derived from /netlib/fdlibm */ 2*37da2899SCharles.Forsyth 3*37da2899SCharles.Forsyth /* @(#)e_fmod.c 1.3 95/01/18 */ 4*37da2899SCharles.Forsyth /* 5*37da2899SCharles.Forsyth * ==================================================== 6*37da2899SCharles.Forsyth * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. 7*37da2899SCharles.Forsyth * 8*37da2899SCharles.Forsyth * Developed at SunSoft, a Sun Microsystems, Inc. business. 9*37da2899SCharles.Forsyth * Permission to use, copy, modify, and distribute this 10*37da2899SCharles.Forsyth * software is freely granted, provided that this notice 11*37da2899SCharles.Forsyth * is preserved. 12*37da2899SCharles.Forsyth * ==================================================== 13*37da2899SCharles.Forsyth */ 14*37da2899SCharles.Forsyth 15*37da2899SCharles.Forsyth /* 16*37da2899SCharles.Forsyth * __ieee754_fmod(x,y) 17*37da2899SCharles.Forsyth * Return x mod y in exact arithmetic 18*37da2899SCharles.Forsyth * Method: shift and subtract 19*37da2899SCharles.Forsyth */ 20*37da2899SCharles.Forsyth 21*37da2899SCharles.Forsyth #include "fdlibm.h" 22*37da2899SCharles.Forsyth 23*37da2899SCharles.Forsyth static const double one = 1.0, Zero[] = {0.0, -0.0,}; 24*37da2899SCharles.Forsyth __ieee754_fmod(double x,double y)25*37da2899SCharles.Forsyth double __ieee754_fmod(double x, double y) 26*37da2899SCharles.Forsyth { 27*37da2899SCharles.Forsyth int n,hx,hy,hz,ix,iy,sx,i; 28*37da2899SCharles.Forsyth unsigned lx,ly,lz; 29*37da2899SCharles.Forsyth 30*37da2899SCharles.Forsyth hx = __HI(x); /* high word of x */ 31*37da2899SCharles.Forsyth lx = __LO(x); /* low word of x */ 32*37da2899SCharles.Forsyth hy = __HI(y); /* high word of y */ 33*37da2899SCharles.Forsyth ly = __LO(y); /* low word of y */ 34*37da2899SCharles.Forsyth sx = hx&0x80000000; /* sign of x */ 35*37da2899SCharles.Forsyth hx ^=sx; /* |x| */ 36*37da2899SCharles.Forsyth hy &= 0x7fffffff; /* |y| */ 37*37da2899SCharles.Forsyth 38*37da2899SCharles.Forsyth /* purge off exception values */ 39*37da2899SCharles.Forsyth if((hy|ly)==0||(hx>=0x7ff00000)|| /* y=0,or x not finite */ 40*37da2899SCharles.Forsyth ((hy|((ly|-ly)>>31))>0x7ff00000)) /* or y is NaN */ 41*37da2899SCharles.Forsyth return (x*y)/(x*y); 42*37da2899SCharles.Forsyth if(hx<=hy) { 43*37da2899SCharles.Forsyth if((hx<hy)||(lx<ly)) return x; /* |x|<|y| return x */ 44*37da2899SCharles.Forsyth if(lx==ly) 45*37da2899SCharles.Forsyth return Zero[(unsigned)sx>>31]; /* |x|=|y| return x*0*/ 46*37da2899SCharles.Forsyth } 47*37da2899SCharles.Forsyth 48*37da2899SCharles.Forsyth /* determine ix = ilogb(x) */ 49*37da2899SCharles.Forsyth if(hx<0x00100000) { /* subnormal x */ 50*37da2899SCharles.Forsyth if(hx==0) { 51*37da2899SCharles.Forsyth for (ix = -1043, i=lx; i>0; i<<=1) ix -=1; 52*37da2899SCharles.Forsyth } else { 53*37da2899SCharles.Forsyth for (ix = -1022,i=(hx<<11); i>0; i<<=1) ix -=1; 54*37da2899SCharles.Forsyth } 55*37da2899SCharles.Forsyth } else ix = (hx>>20)-1023; 56*37da2899SCharles.Forsyth 57*37da2899SCharles.Forsyth /* determine iy = ilogb(y) */ 58*37da2899SCharles.Forsyth if(hy<0x00100000) { /* subnormal y */ 59*37da2899SCharles.Forsyth if(hy==0) { 60*37da2899SCharles.Forsyth for (iy = -1043, i=ly; i>0; i<<=1) iy -=1; 61*37da2899SCharles.Forsyth } else { 62*37da2899SCharles.Forsyth for (iy = -1022,i=(hy<<11); i>0; i<<=1) iy -=1; 63*37da2899SCharles.Forsyth } 64*37da2899SCharles.Forsyth } else iy = (hy>>20)-1023; 65*37da2899SCharles.Forsyth 66*37da2899SCharles.Forsyth /* set up {hx,lx}, {hy,ly} and align y to x */ 67*37da2899SCharles.Forsyth if(ix >= -1022) 68*37da2899SCharles.Forsyth hx = 0x00100000|(0x000fffff&hx); 69*37da2899SCharles.Forsyth else { /* subnormal x, shift x to normal */ 70*37da2899SCharles.Forsyth n = -1022-ix; 71*37da2899SCharles.Forsyth if(n<=31) { 72*37da2899SCharles.Forsyth hx = (hx<<n)|(lx>>(32-n)); 73*37da2899SCharles.Forsyth lx <<= n; 74*37da2899SCharles.Forsyth } else { 75*37da2899SCharles.Forsyth hx = lx<<(n-32); 76*37da2899SCharles.Forsyth lx = 0; 77*37da2899SCharles.Forsyth } 78*37da2899SCharles.Forsyth } 79*37da2899SCharles.Forsyth if(iy >= -1022) 80*37da2899SCharles.Forsyth hy = 0x00100000|(0x000fffff&hy); 81*37da2899SCharles.Forsyth else { /* subnormal y, shift y to normal */ 82*37da2899SCharles.Forsyth n = -1022-iy; 83*37da2899SCharles.Forsyth if(n<=31) { 84*37da2899SCharles.Forsyth hy = (hy<<n)|(ly>>(32-n)); 85*37da2899SCharles.Forsyth ly <<= n; 86*37da2899SCharles.Forsyth } else { 87*37da2899SCharles.Forsyth hy = ly<<(n-32); 88*37da2899SCharles.Forsyth ly = 0; 89*37da2899SCharles.Forsyth } 90*37da2899SCharles.Forsyth } 91*37da2899SCharles.Forsyth 92*37da2899SCharles.Forsyth /* fix point fmod */ 93*37da2899SCharles.Forsyth n = ix - iy; 94*37da2899SCharles.Forsyth while(n--) { 95*37da2899SCharles.Forsyth hz=hx-hy;lz=lx-ly; if(lx<ly) hz -= 1; 96*37da2899SCharles.Forsyth if(hz<0){hx = hx+hx+(lx>>31); lx = lx+lx;} 97*37da2899SCharles.Forsyth else { 98*37da2899SCharles.Forsyth if((hz|lz)==0) /* return sign(x)*0 */ 99*37da2899SCharles.Forsyth return Zero[(unsigned)sx>>31]; 100*37da2899SCharles.Forsyth hx = hz+hz+(lz>>31); lx = lz+lz; 101*37da2899SCharles.Forsyth } 102*37da2899SCharles.Forsyth } 103*37da2899SCharles.Forsyth hz=hx-hy;lz=lx-ly; if(lx<ly) hz -= 1; 104*37da2899SCharles.Forsyth if(hz>=0) {hx=hz;lx=lz;} 105*37da2899SCharles.Forsyth 106*37da2899SCharles.Forsyth /* convert back to floating value and restore the sign */ 107*37da2899SCharles.Forsyth if((hx|lx)==0) /* return sign(x)*0 */ 108*37da2899SCharles.Forsyth return Zero[(unsigned)sx>>31]; 109*37da2899SCharles.Forsyth while(hx<0x00100000) { /* normalize x */ 110*37da2899SCharles.Forsyth hx = hx+hx+(lx>>31); lx = lx+lx; 111*37da2899SCharles.Forsyth iy -= 1; 112*37da2899SCharles.Forsyth } 113*37da2899SCharles.Forsyth if(iy>= -1022) { /* normalize output */ 114*37da2899SCharles.Forsyth hx = ((hx-0x00100000)|((iy+1023)<<20)); 115*37da2899SCharles.Forsyth __HI(x) = hx|sx; 116*37da2899SCharles.Forsyth __LO(x) = lx; 117*37da2899SCharles.Forsyth } else { /* subnormal output */ 118*37da2899SCharles.Forsyth n = -1022 - iy; 119*37da2899SCharles.Forsyth if(n<=20) { 120*37da2899SCharles.Forsyth lx = (lx>>n)|((unsigned)hx<<(32-n)); 121*37da2899SCharles.Forsyth hx >>= n; 122*37da2899SCharles.Forsyth } else if (n<=31) { 123*37da2899SCharles.Forsyth lx = (hx<<(32-n))|(lx>>n); hx = sx; 124*37da2899SCharles.Forsyth } else { 125*37da2899SCharles.Forsyth lx = hx>>(n-32); hx = sx; 126*37da2899SCharles.Forsyth } 127*37da2899SCharles.Forsyth __HI(x) = hx|sx; 128*37da2899SCharles.Forsyth __LO(x) = lx; 129*37da2899SCharles.Forsyth x *= one; /* create necessary signal */ 130*37da2899SCharles.Forsyth } 131*37da2899SCharles.Forsyth return x; /* exact output */ 132*37da2899SCharles.Forsyth } 133