xref: /openbsd-src/lib/libm/src/e_rem_pio2.c (revision 043fbe51c197dbbcd422e917b65f765d8b5f8874)
1df930be7Sderaadt /* @(#)e_rem_pio2.c 5.1 93/09/24 */
2df930be7Sderaadt /*
3df930be7Sderaadt  * ====================================================
4df930be7Sderaadt  * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
5df930be7Sderaadt  *
6df930be7Sderaadt  * Developed at SunPro, a Sun Microsystems, Inc. business.
7df930be7Sderaadt  * Permission to use, copy, modify, and distribute this
8df930be7Sderaadt  * software is freely granted, provided that this notice
9df930be7Sderaadt  * is preserved.
10df930be7Sderaadt  * ====================================================
11df930be7Sderaadt  */
12df930be7Sderaadt 
13df930be7Sderaadt /* __ieee754_rem_pio2(x,y)
14df930be7Sderaadt  *
15df930be7Sderaadt  * return the remainder of x rem pi/2 in y[0]+y[1]
16df930be7Sderaadt  * use __kernel_rem_pio2()
17df930be7Sderaadt  */
18df930be7Sderaadt 
19df930be7Sderaadt #include "math.h"
20df930be7Sderaadt #include "math_private.h"
21df930be7Sderaadt 
22df930be7Sderaadt static const int32_t npio2_hw[] = {
23df930be7Sderaadt 0x3FF921FB, 0x400921FB, 0x4012D97C, 0x401921FB, 0x401F6A7A, 0x4022D97C,
24df930be7Sderaadt 0x4025FDBB, 0x402921FB, 0x402C463A, 0x402F6A7A, 0x4031475C, 0x4032D97C,
25df930be7Sderaadt 0x40346B9C, 0x4035FDBB, 0x40378FDB, 0x403921FB, 0x403AB41B, 0x403C463A,
26df930be7Sderaadt 0x403DD85A, 0x403F6A7A, 0x40407E4C, 0x4041475C, 0x4042106C, 0x4042D97C,
27df930be7Sderaadt 0x4043A28C, 0x40446B9C, 0x404534AC, 0x4045FDBB, 0x4046C6CB, 0x40478FDB,
28df930be7Sderaadt 0x404858EB, 0x404921FB,
29df930be7Sderaadt };
30df930be7Sderaadt 
31df930be7Sderaadt /*
32df930be7Sderaadt  * invpio2:  53 bits of 2/pi
33df930be7Sderaadt  * pio2_1:   first  33 bit of pi/2
34df930be7Sderaadt  * pio2_1t:  pi/2 - pio2_1
35df930be7Sderaadt  * pio2_2:   second 33 bit of pi/2
36df930be7Sderaadt  * pio2_2t:  pi/2 - (pio2_1+pio2_2)
37df930be7Sderaadt  * pio2_3:   third  33 bit of pi/2
38df930be7Sderaadt  * pio2_3t:  pi/2 - (pio2_1+pio2_2+pio2_3)
39df930be7Sderaadt  */
40df930be7Sderaadt 
41df930be7Sderaadt static const double
42df930be7Sderaadt zero =  0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */
43df930be7Sderaadt half =  5.00000000000000000000e-01, /* 0x3FE00000, 0x00000000 */
44df930be7Sderaadt two24 =  1.67772160000000000000e+07, /* 0x41700000, 0x00000000 */
45df930be7Sderaadt invpio2 =  6.36619772367581382433e-01, /* 0x3FE45F30, 0x6DC9C883 */
46df930be7Sderaadt pio2_1  =  1.57079632673412561417e+00, /* 0x3FF921FB, 0x54400000 */
47df930be7Sderaadt pio2_1t =  6.07710050650619224932e-11, /* 0x3DD0B461, 0x1A626331 */
48df930be7Sderaadt pio2_2  =  6.07710050630396597660e-11, /* 0x3DD0B461, 0x1A600000 */
49df930be7Sderaadt pio2_2t =  2.02226624879595063154e-21, /* 0x3BA3198A, 0x2E037073 */
50df930be7Sderaadt pio2_3  =  2.02226624871116645580e-21, /* 0x3BA3198A, 0x2E000000 */
51df930be7Sderaadt pio2_3t =  8.47842766036889956997e-32; /* 0x397B839A, 0x252049C1 */
52df930be7Sderaadt 
53e7beb4a7Smillert int32_t
__ieee754_rem_pio2(double x,double * y)54e7beb4a7Smillert __ieee754_rem_pio2(double x, double *y)
55df930be7Sderaadt {
56df930be7Sderaadt 	double z,w,t,r,fn;
57df930be7Sderaadt 	double tx[3];
58df930be7Sderaadt 	int32_t e0,i,j,nx,n,ix,hx;
59df930be7Sderaadt 	u_int32_t low;
60df930be7Sderaadt 
61df930be7Sderaadt 	GET_HIGH_WORD(hx,x);		/* high word of x */
62df930be7Sderaadt 	ix = hx&0x7fffffff;
63df930be7Sderaadt 	if(ix<=0x3fe921fb)   /* |x| ~<= pi/4 , no need for reduction */
64df930be7Sderaadt 	    {y[0] = x; y[1] = 0; return 0;}
65df930be7Sderaadt 	if(ix<0x4002d97c) {  /* |x| < 3pi/4, special case with n=+-1 */
66df930be7Sderaadt 	    if(hx>0) {
67df930be7Sderaadt 		z = x - pio2_1;
68df930be7Sderaadt 		if(ix!=0x3ff921fb) { 	/* 33+53 bit pi is good enough */
69df930be7Sderaadt 		    y[0] = z - pio2_1t;
70df930be7Sderaadt 		    y[1] = (z-y[0])-pio2_1t;
71df930be7Sderaadt 		} else {		/* near pi/2, use 33+33+53 bit pi */
72df930be7Sderaadt 		    z -= pio2_2;
73df930be7Sderaadt 		    y[0] = z - pio2_2t;
74df930be7Sderaadt 		    y[1] = (z-y[0])-pio2_2t;
75df930be7Sderaadt 		}
76df930be7Sderaadt 		return 1;
77df930be7Sderaadt 	    } else {	/* negative x */
78df930be7Sderaadt 		z = x + pio2_1;
79df930be7Sderaadt 		if(ix!=0x3ff921fb) { 	/* 33+53 bit pi is good enough */
80df930be7Sderaadt 		    y[0] = z + pio2_1t;
81df930be7Sderaadt 		    y[1] = (z-y[0])+pio2_1t;
82df930be7Sderaadt 		} else {		/* near pi/2, use 33+33+53 bit pi */
83df930be7Sderaadt 		    z += pio2_2;
84df930be7Sderaadt 		    y[0] = z + pio2_2t;
85df930be7Sderaadt 		    y[1] = (z-y[0])+pio2_2t;
86df930be7Sderaadt 		}
87df930be7Sderaadt 		return -1;
88df930be7Sderaadt 	    }
89df930be7Sderaadt 	}
90df930be7Sderaadt 	if(ix<=0x413921fb) { /* |x| ~<= 2^19*(pi/2), medium size */
91df930be7Sderaadt 	    t  = fabs(x);
92df930be7Sderaadt 	    n  = (int32_t) (t*invpio2+half);
93df930be7Sderaadt 	    fn = (double)n;
94df930be7Sderaadt 	    r  = t-fn*pio2_1;
95df930be7Sderaadt 	    w  = fn*pio2_1t;	/* 1st round good to 85 bit */
96df930be7Sderaadt 	    if(n<32&&ix!=npio2_hw[n-1]) {
97df930be7Sderaadt 		y[0] = r-w;	/* quick check no cancellation */
98df930be7Sderaadt 	    } else {
99df930be7Sderaadt 	        u_int32_t high;
100df930be7Sderaadt 	        j  = ix>>20;
101df930be7Sderaadt 	        y[0] = r-w;
102df930be7Sderaadt 		GET_HIGH_WORD(high,y[0]);
103df930be7Sderaadt 	        i = j-((high>>20)&0x7ff);
104df930be7Sderaadt 	        if(i>16) {  /* 2nd iteration needed, good to 118 */
105df930be7Sderaadt 		    t  = r;
106df930be7Sderaadt 		    w  = fn*pio2_2;
107df930be7Sderaadt 		    r  = t-w;
108df930be7Sderaadt 		    w  = fn*pio2_2t-((t-r)-w);
109df930be7Sderaadt 		    y[0] = r-w;
110df930be7Sderaadt 		    GET_HIGH_WORD(high,y[0]);
111df930be7Sderaadt 		    i = j-((high>>20)&0x7ff);
112df930be7Sderaadt 		    if(i>49)  {	/* 3rd iteration need, 151 bits acc */
113df930be7Sderaadt 		    	t  = r;	/* will cover all possible cases */
114df930be7Sderaadt 		    	w  = fn*pio2_3;
115df930be7Sderaadt 		    	r  = t-w;
116df930be7Sderaadt 		    	w  = fn*pio2_3t-((t-r)-w);
117df930be7Sderaadt 		    	y[0] = r-w;
118df930be7Sderaadt 		    }
119df930be7Sderaadt 		}
120df930be7Sderaadt 	    }
121df930be7Sderaadt 	    y[1] = (r-y[0])-w;
122df930be7Sderaadt 	    if(hx<0) 	{y[0] = -y[0]; y[1] = -y[1]; return -n;}
123df930be7Sderaadt 	    else	 return n;
124df930be7Sderaadt 	}
125df930be7Sderaadt     /*
126df930be7Sderaadt      * all other (large) arguments
127df930be7Sderaadt      */
128df930be7Sderaadt 	if(ix>=0x7ff00000) {		/* x is inf or NaN */
129df930be7Sderaadt 	    y[0]=y[1]=x-x; return 0;
130df930be7Sderaadt 	}
131df930be7Sderaadt     /* set z = scalbn(|x|,ilogb(x)-23) */
132df930be7Sderaadt 	GET_LOW_WORD(low,x);
133df930be7Sderaadt 	SET_LOW_WORD(z,low);
134df930be7Sderaadt 	e0 	= (ix>>20)-1046;	/* e0 = ilogb(z)-23; */
135df930be7Sderaadt 	SET_HIGH_WORD(z, ix - ((int32_t)(e0<<20)));
136df930be7Sderaadt 	for(i=0;i<2;i++) {
137df930be7Sderaadt 		tx[i] = (double)((int32_t)(z));
138df930be7Sderaadt 		z     = (z-tx[i])*two24;
139df930be7Sderaadt 	}
140df930be7Sderaadt 	tx[2] = z;
141df930be7Sderaadt 	nx = 3;
142df930be7Sderaadt 	while(tx[nx-1]==zero) nx--;	/* skip zero term */
143*390c8400Smartynas 	n  =  __kernel_rem_pio2(tx,y,e0,nx,2);
144df930be7Sderaadt 	if(hx<0) {y[0] = -y[0]; y[1] = -y[1]; return -n;}
145df930be7Sderaadt 	return n;
146df930be7Sderaadt }
147