13a8617a8SJordan K. Hubbard /* e_fmodf.c -- float version of e_fmod.c. 23a8617a8SJordan K. Hubbard * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. 33a8617a8SJordan K. Hubbard */ 43a8617a8SJordan K. Hubbard 53a8617a8SJordan K. Hubbard /* 63a8617a8SJordan K. Hubbard * ==================================================== 73a8617a8SJordan K. Hubbard * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. 83a8617a8SJordan K. Hubbard * 93a8617a8SJordan K. Hubbard * Developed at SunPro, a Sun Microsystems, Inc. business. 103a8617a8SJordan K. Hubbard * Permission to use, copy, modify, and distribute this 113a8617a8SJordan K. Hubbard * software is freely granted, provided that this notice 123a8617a8SJordan K. Hubbard * is preserved. 133a8617a8SJordan K. Hubbard * ==================================================== 143a8617a8SJordan K. Hubbard */ 153a8617a8SJordan K. Hubbard 163a8617a8SJordan K. Hubbard #ifndef lint 173a8617a8SJordan K. Hubbard static char rcsid[] = "$Id: e_fmodf.c,v 1.2 1994/08/18 23:05:23 jtc Exp $"; 183a8617a8SJordan K. Hubbard #endif 193a8617a8SJordan K. Hubbard 203a8617a8SJordan K. Hubbard /* 213a8617a8SJordan K. Hubbard * __ieee754_fmodf(x,y) 223a8617a8SJordan K. Hubbard * Return x mod y in exact arithmetic 233a8617a8SJordan K. Hubbard * Method: shift and subtract 243a8617a8SJordan K. Hubbard */ 253a8617a8SJordan K. Hubbard 263a8617a8SJordan K. Hubbard #include "math.h" 273a8617a8SJordan K. Hubbard #include "math_private.h" 283a8617a8SJordan K. Hubbard 293a8617a8SJordan K. Hubbard #ifdef __STDC__ 303a8617a8SJordan K. Hubbard static const float one = 1.0, Zero[] = {0.0, -0.0,}; 313a8617a8SJordan K. Hubbard #else 323a8617a8SJordan K. Hubbard static float one = 1.0, Zero[] = {0.0, -0.0,}; 333a8617a8SJordan K. Hubbard #endif 343a8617a8SJordan K. Hubbard 353a8617a8SJordan K. Hubbard #ifdef __STDC__ 363a8617a8SJordan K. Hubbard float __ieee754_fmodf(float x, float y) 373a8617a8SJordan K. Hubbard #else 383a8617a8SJordan K. Hubbard float __ieee754_fmodf(x,y) 393a8617a8SJordan K. Hubbard float x,y ; 403a8617a8SJordan K. Hubbard #endif 413a8617a8SJordan K. Hubbard { 423a8617a8SJordan K. Hubbard int32_t n,hx,hy,hz,ix,iy,sx,i; 433a8617a8SJordan K. Hubbard 443a8617a8SJordan K. Hubbard GET_FLOAT_WORD(hx,x); 453a8617a8SJordan K. Hubbard GET_FLOAT_WORD(hy,y); 463a8617a8SJordan K. Hubbard sx = hx&0x80000000; /* sign of x */ 473a8617a8SJordan K. Hubbard hx ^=sx; /* |x| */ 483a8617a8SJordan K. Hubbard hy &= 0x7fffffff; /* |y| */ 493a8617a8SJordan K. Hubbard 503a8617a8SJordan K. Hubbard /* purge off exception values */ 513a8617a8SJordan K. Hubbard if(hy==0||(hx>=0x7f800000)|| /* y=0,or x not finite */ 523a8617a8SJordan K. Hubbard (hy>0x7f800000)) /* or y is NaN */ 533a8617a8SJordan K. Hubbard return (x*y)/(x*y); 543a8617a8SJordan K. Hubbard if(hx<hy) return x; /* |x|<|y| return x */ 553a8617a8SJordan K. Hubbard if(hx==hy) 563a8617a8SJordan K. Hubbard return Zero[(u_int32_t)sx>>31]; /* |x|=|y| return x*0*/ 573a8617a8SJordan K. Hubbard 583a8617a8SJordan K. Hubbard /* determine ix = ilogb(x) */ 593a8617a8SJordan K. Hubbard if(hx<0x00800000) { /* subnormal x */ 603a8617a8SJordan K. Hubbard for (ix = -126,i=(hx<<8); i>0; i<<=1) ix -=1; 613a8617a8SJordan K. Hubbard } else ix = (hx>>23)-127; 623a8617a8SJordan K. Hubbard 633a8617a8SJordan K. Hubbard /* determine iy = ilogb(y) */ 643a8617a8SJordan K. Hubbard if(hy<0x00800000) { /* subnormal y */ 653a8617a8SJordan K. Hubbard for (iy = -126,i=(hy<<8); i>=0; i<<=1) iy -=1; 663a8617a8SJordan K. Hubbard } else iy = (hy>>23)-127; 673a8617a8SJordan K. Hubbard 683a8617a8SJordan K. Hubbard /* set up {hx,lx}, {hy,ly} and align y to x */ 693a8617a8SJordan K. Hubbard if(ix >= -126) 703a8617a8SJordan K. Hubbard hx = 0x00800000|(0x007fffff&hx); 713a8617a8SJordan K. Hubbard else { /* subnormal x, shift x to normal */ 723a8617a8SJordan K. Hubbard n = -126-ix; 733a8617a8SJordan K. Hubbard hx = hx<<n; 743a8617a8SJordan K. Hubbard } 753a8617a8SJordan K. Hubbard if(iy >= -126) 763a8617a8SJordan K. Hubbard hy = 0x00800000|(0x007fffff&hy); 773a8617a8SJordan K. Hubbard else { /* subnormal y, shift y to normal */ 783a8617a8SJordan K. Hubbard n = -126-iy; 793a8617a8SJordan K. Hubbard hy = hy<<n; 803a8617a8SJordan K. Hubbard } 813a8617a8SJordan K. Hubbard 823a8617a8SJordan K. Hubbard /* fix point fmod */ 833a8617a8SJordan K. Hubbard n = ix - iy; 843a8617a8SJordan K. Hubbard while(n--) { 853a8617a8SJordan K. Hubbard hz=hx-hy; 863a8617a8SJordan K. Hubbard if(hz<0){hx = hx+hx;} 873a8617a8SJordan K. Hubbard else { 883a8617a8SJordan K. Hubbard if(hz==0) /* return sign(x)*0 */ 893a8617a8SJordan K. Hubbard return Zero[(u_int32_t)sx>>31]; 903a8617a8SJordan K. Hubbard hx = hz+hz; 913a8617a8SJordan K. Hubbard } 923a8617a8SJordan K. Hubbard } 933a8617a8SJordan K. Hubbard hz=hx-hy; 943a8617a8SJordan K. Hubbard if(hz>=0) {hx=hz;} 953a8617a8SJordan K. Hubbard 963a8617a8SJordan K. Hubbard /* convert back to floating value and restore the sign */ 973a8617a8SJordan K. Hubbard if(hx==0) /* return sign(x)*0 */ 983a8617a8SJordan K. Hubbard return Zero[(u_int32_t)sx>>31]; 993a8617a8SJordan K. Hubbard while(hx<0x00800000) { /* normalize x */ 1003a8617a8SJordan K. Hubbard hx = hx+hx; 1013a8617a8SJordan K. Hubbard iy -= 1; 1023a8617a8SJordan K. Hubbard } 1033a8617a8SJordan K. Hubbard if(iy>= -126) { /* normalize output */ 1043a8617a8SJordan K. Hubbard hx = ((hx-0x00800000)|((iy+127)<<23)); 1053a8617a8SJordan K. Hubbard SET_FLOAT_WORD(x,hx|sx); 1063a8617a8SJordan K. Hubbard } else { /* subnormal output */ 1073a8617a8SJordan K. Hubbard n = -126 - iy; 1083a8617a8SJordan K. Hubbard hx >>= n; 1093a8617a8SJordan K. Hubbard SET_FLOAT_WORD(x,hx|sx); 1103a8617a8SJordan K. Hubbard x *= one; /* create necessary signal */ 1113a8617a8SJordan K. Hubbard } 1123a8617a8SJordan K. Hubbard return x; /* exact output */ 1133a8617a8SJordan K. Hubbard } 114