xref: /inferno-os/libmath/fdlibm/e_fmod.c (revision 37da2899f40661e3e9631e497da8dc59b971cbd0)
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