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