Replace FSF snail mail address with URLs.
[glibc.git] / sysdeps / ieee754 / dbl-64 / sincos32.c
blobf3418fe96464befe3139be3d74477a2f4918abe0
1 /*
2 * IBM Accurate Mathematical Library
3 * written by International Business Machines Corp.
4 * Copyright (C) 2001, 2011 Free Software Foundation
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation; either version 2.1 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
19 /****************************************************************/
20 /* MODULE_NAME: sincos32.c */
21 /* */
22 /* FUNCTIONS: ss32 */
23 /* cc32 */
24 /* c32 */
25 /* sin32 */
26 /* cos32 */
27 /* mpsin */
28 /* mpcos */
29 /* mpranred */
30 /* mpsin1 */
31 /* mpcos1 */
32 /* */
33 /* FILES NEEDED: endian.h mpa.h sincos32.h */
34 /* mpa.c */
35 /* */
36 /* Multi Precision sin() and cos() function with p=32 for sin()*/
37 /* cos() arcsin() and arccos() routines */
38 /* In addition mpranred() routine performs range reduction of */
39 /* a double number x into multi precision number y, */
40 /* such that y=x-n*pi/2, abs(y)<pi/4, n=0,+-1,+-2,.... */
41 /****************************************************************/
42 #include "endian.h"
43 #include "mpa.h"
44 #include "sincos32.h"
45 #include "math_private.h"
47 #ifndef SECTION
48 # define SECTION
49 #endif
51 /****************************************************************/
52 /* Compute Multi-Precision sin() function for given p. Receive */
53 /* Multi Precision number x and result stored at y */
54 /****************************************************************/
55 static void
56 SECTION
57 ss32(mp_no *x, mp_no *y, int p) {
58 int i;
59 double a;
60 #if 0
61 double b;
62 static const mp_no mpone = {1,{1.0,1.0}};
63 #endif
64 mp_no mpt1,x2,gor,sum ,mpk={1,{1.0}};
65 #if 0
66 mp_no mpt2;
67 #endif
68 for (i=1;i<=p;i++) mpk.d[i]=0;
70 __mul(x,x,&x2,p);
71 __cpy(&oofac27,&gor,p);
72 __cpy(&gor,&sum,p);
73 for (a=27.0;a>1.0;a-=2.0) {
74 mpk.d[1]=a*(a-1.0);
75 __mul(&gor,&mpk,&mpt1,p);
76 __cpy(&mpt1,&gor,p);
77 __mul(&x2,&sum,&mpt1,p);
78 __sub(&gor,&mpt1,&sum,p);
80 __mul(x,&sum,y,p);
83 /**********************************************************************/
84 /* Compute Multi-Precision cos() function for given p. Receive Multi */
85 /* Precision number x and result stored at y */
86 /**********************************************************************/
87 static void
88 SECTION
89 cc32(mp_no *x, mp_no *y, int p) {
90 int i;
91 double a;
92 #if 0
93 double b;
94 static const mp_no mpone = {1,{1.0,1.0}};
95 #endif
96 mp_no mpt1,x2,gor,sum ,mpk={1,{1.0}};
97 #if 0
98 mp_no mpt2;
99 #endif
100 for (i=1;i<=p;i++) mpk.d[i]=0;
102 __mul(x,x,&x2,p);
103 mpk.d[1]=27.0;
104 __mul(&oofac27,&mpk,&gor,p);
105 __cpy(&gor,&sum,p);
106 for (a=26.0;a>2.0;a-=2.0) {
107 mpk.d[1]=a*(a-1.0);
108 __mul(&gor,&mpk,&mpt1,p);
109 __cpy(&mpt1,&gor,p);
110 __mul(&x2,&sum,&mpt1,p);
111 __sub(&gor,&mpt1,&sum,p);
113 __mul(&x2,&sum,y,p);
116 /***************************************************************************/
117 /* c32() computes both sin(x), cos(x) as Multi precision numbers */
118 /***************************************************************************/
119 void
120 SECTION
121 __c32(mp_no *x, mp_no *y, mp_no *z, int p) {
122 static const mp_no mpt={1,{1.0,2.0}}, one={1,{1.0,1.0}};
123 mp_no u,t,t1,t2,c,s;
124 int i;
125 __cpy(x,&u,p);
126 u.e=u.e-1;
127 cc32(&u,&c,p);
128 ss32(&u,&s,p);
129 for (i=0;i<24;i++) {
130 __mul(&c,&s,&t,p);
131 __sub(&s,&t,&t1,p);
132 __add(&t1,&t1,&s,p);
133 __sub(&mpt,&c,&t1,p);
134 __mul(&t1,&c,&t2,p);
135 __add(&t2,&t2,&c,p);
137 __sub(&one,&c,y,p);
138 __cpy(&s,z,p);
141 /************************************************************************/
142 /*Routine receive double x and two double results of sin(x) and return */
143 /*result which is more accurate */
144 /*Computing sin(x) with multi precision routine c32 */
145 /************************************************************************/
146 double
147 SECTION
148 __sin32(double x, double res, double res1) {
149 int p;
150 mp_no a,b,c;
151 p=32;
152 __dbl_mp(res,&a,p);
153 __dbl_mp(0.5*(res1-res),&b,p);
154 __add(&a,&b,&c,p);
155 if (x>0.8)
156 { __sub(&hp,&c,&a,p);
157 __c32(&a,&b,&c,p);
159 else __c32(&c,&a,&b,p); /* b=sin(0.5*(res+res1)) */
160 __dbl_mp(x,&c,p); /* c = x */
161 __sub(&b,&c,&a,p);
162 /* if a>0 return min(res,res1), otherwise return max(res,res1) */
163 if (a.d[0]>0) return (res<res1)?res:res1;
164 else return (res>res1)?res:res1;
167 /************************************************************************/
168 /*Routine receive double x and two double results of cos(x) and return */
169 /*result which is more accurate */
170 /*Computing cos(x) with multi precision routine c32 */
171 /************************************************************************/
172 double
173 SECTION
174 __cos32(double x, double res, double res1) {
175 int p;
176 mp_no a,b,c;
177 p=32;
178 __dbl_mp(res,&a,p);
179 __dbl_mp(0.5*(res1-res),&b,p);
180 __add(&a,&b,&c,p);
181 if (x>2.4)
182 { __sub(&pi,&c,&a,p);
183 __c32(&a,&b,&c,p);
184 b.d[0]=-b.d[0];
186 else if (x>0.8)
187 { __sub(&hp,&c,&a,p);
188 __c32(&a,&c,&b,p);
190 else __c32(&c,&b,&a,p); /* b=cos(0.5*(res+res1)) */
191 __dbl_mp(x,&c,p); /* c = x */
192 __sub(&b,&c,&a,p);
193 /* if a>0 return max(res,res1), otherwise return min(res,res1) */
194 if (a.d[0]>0) return (res>res1)?res:res1;
195 else return (res<res1)?res:res1;
198 /*******************************************************************/
199 /*Compute sin(x+dx) as Multi Precision number and return result as */
200 /* double */
201 /*******************************************************************/
202 double
203 SECTION
204 __mpsin(double x, double dx) {
205 int p;
206 double y;
207 mp_no a,b,c;
208 p=32;
209 __dbl_mp(x,&a,p);
210 __dbl_mp(dx,&b,p);
211 __add(&a,&b,&c,p);
212 if (x>0.8) { __sub(&hp,&c,&a,p); __c32(&a,&b,&c,p); }
213 else __c32(&c,&a,&b,p); /* b = sin(x+dx) */
214 __mp_dbl(&b,&y,p);
215 return y;
218 /*******************************************************************/
219 /* Compute cos()of double-length number (x+dx) as Multi Precision */
220 /* number and return result as double */
221 /*******************************************************************/
222 double
223 SECTION
224 __mpcos(double x, double dx) {
225 int p;
226 double y;
227 mp_no a,b,c;
228 p=32;
229 __dbl_mp(x,&a,p);
230 __dbl_mp(dx,&b,p);
231 __add(&a,&b,&c,p);
232 if (x>0.8)
233 { __sub(&hp,&c,&b,p);
234 __c32(&b,&c,&a,p);
236 else __c32(&c,&a,&b,p); /* a = cos(x+dx) */
237 __mp_dbl(&a,&y,p);
238 return y;
241 /******************************************************************/
242 /* mpranred() performs range reduction of a double number x into */
243 /* multi precision number y, such that y=x-n*pi/2, abs(y)<pi/4, */
244 /* n=0,+-1,+-2,.... */
245 /* Return int which indicates in which quarter of circle x is */
246 /******************************************************************/
248 SECTION
249 __mpranred(double x, mp_no *y, int p)
251 number v;
252 double t,xn;
253 int i,k,n;
254 static const mp_no one = {1,{1.0,1.0}};
255 mp_no a,b,c;
257 if (ABS(x) < 2.8e14) {
258 t = (x*hpinv.d + toint.d);
259 xn = t - toint.d;
260 v.d = t;
261 n =v.i[LOW_HALF]&3;
262 __dbl_mp(xn,&a,p);
263 __mul(&a,&hp,&b,p);
264 __dbl_mp(x,&c,p);
265 __sub(&c,&b,y,p);
266 return n;
268 else { /* if x is very big more precision required */
269 __dbl_mp(x,&a,p);
270 a.d[0]=1.0;
271 k = a.e-5;
272 if (k < 0) k=0;
273 b.e = -k;
274 b.d[0] = 1.0;
275 for (i=0;i<p;i++) b.d[i+1] = toverp[i+k];
276 __mul(&a,&b,&c,p);
277 t = c.d[c.e];
278 for (i=1;i<=p-c.e;i++) c.d[i]=c.d[i+c.e];
279 for (i=p+1-c.e;i<=p;i++) c.d[i]=0;
280 c.e=0;
281 if (c.d[1] >= 8388608.0)
282 { t +=1.0;
283 __sub(&c,&one,&b,p);
284 __mul(&b,&hp,y,p);
286 else __mul(&c,&hp,y,p);
287 n = (int) t;
288 if (x < 0) { y->d[0] = - y->d[0]; n = -n; }
289 return (n&3);
293 /*******************************************************************/
294 /* Multi-Precision sin() function subroutine, for p=32. It is */
295 /* based on the routines mpranred() and c32(). */
296 /*******************************************************************/
297 double
298 SECTION
299 __mpsin1(double x)
301 int p;
302 int n;
303 mp_no u,s,c;
304 double y;
305 p=32;
306 n=__mpranred(x,&u,p); /* n is 0, 1, 2 or 3 */
307 __c32(&u,&c,&s,p);
308 switch (n) { /* in which quarter of unit circle y is*/
309 case 0:
310 __mp_dbl(&s,&y,p);
311 return y;
312 break;
314 case 2:
315 __mp_dbl(&s,&y,p);
316 return -y;
317 break;
319 case 1:
320 __mp_dbl(&c,&y,p);
321 return y;
322 break;
324 case 3:
325 __mp_dbl(&c,&y,p);
326 return -y;
327 break;
330 return 0; /* unreachable, to make the compiler happy */
333 /*****************************************************************/
334 /* Multi-Precision cos() function subroutine, for p=32. It is */
335 /* based on the routines mpranred() and c32(). */
336 /*****************************************************************/
338 double
339 SECTION
340 __mpcos1(double x)
342 int p;
343 int n;
344 mp_no u,s,c;
345 double y;
347 p=32;
348 n=__mpranred(x,&u,p); /* n is 0, 1, 2 or 3 */
349 __c32(&u,&c,&s,p);
350 switch (n) { /* in what quarter of unit circle y is*/
352 case 0:
353 __mp_dbl(&c,&y,p);
354 return y;
355 break;
357 case 2:
358 __mp_dbl(&c,&y,p);
359 return -y;
360 break;
362 case 1:
363 __mp_dbl(&s,&y,p);
364 return -y;
365 break;
367 case 3:
368 __mp_dbl(&s,&y,p);
369 return y;
370 break;
373 return 0; /* unreachable, to make the compiler happy */
375 /******************************************************************/