2 * IBM Accurate Mathematical Library
3 * written by International Business Machines Corp.
4 * Copyright (C) 2001-2014 Free Software Foundation, Inc.
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 */
33 /* FILES NEEDED: endian.h mpa.h sincos32.h */
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 /****************************************************************/
45 #include <math_private.h>
46 #include <stap-probe.h>
52 /* Compute Multi-Precision sin() function for given p. Receive Multi Precision
53 number x and result stored at y. */
56 ss32 (mp_no
*x
, mp_no
*y
, int p
)
60 mp_no mpt1
, x2
, gor
, sum
, mpk
= {1, {1.0}};
61 for (i
= 1; i
<= p
; i
++)
65 __cpy (&oofac27
, &gor
, p
);
66 __cpy (&gor
, &sum
, p
);
67 for (a
= 27.0; a
> 1.0; a
-= 2.0)
69 mpk
.d
[1] = a
* (a
- 1.0);
70 __mul (&gor
, &mpk
, &mpt1
, p
);
71 __cpy (&mpt1
, &gor
, p
);
72 __mul (&x2
, &sum
, &mpt1
, p
);
73 __sub (&gor
, &mpt1
, &sum
, p
);
75 __mul (x
, &sum
, y
, p
);
78 /* Compute Multi-Precision cos() function for given p. Receive Multi Precision
79 number x and result stored at y. */
82 cc32 (mp_no
*x
, mp_no
*y
, int p
)
86 mp_no mpt1
, x2
, gor
, sum
, mpk
= {1, {1.0}};
87 for (i
= 1; i
<= p
; i
++)
92 __mul (&oofac27
, &mpk
, &gor
, p
);
93 __cpy (&gor
, &sum
, p
);
94 for (a
= 26.0; a
> 2.0; a
-= 2.0)
96 mpk
.d
[1] = a
* (a
- 1.0);
97 __mul (&gor
, &mpk
, &mpt1
, p
);
98 __cpy (&mpt1
, &gor
, p
);
99 __mul (&x2
, &sum
, &mpt1
, p
);
100 __sub (&gor
, &mpt1
, &sum
, p
);
102 __mul (&x2
, &sum
, y
, p
);
105 /* Compute both sin(x), cos(x) as Multi precision numbers. */
108 __c32 (mp_no
*x
, mp_no
*y
, mp_no
*z
, int p
)
110 mp_no u
, t
, t1
, t2
, c
, s
;
116 for (i
= 0; i
< 24; i
++)
118 __mul (&c
, &s
, &t
, p
);
119 __sub (&s
, &t
, &t1
, p
);
120 __add (&t1
, &t1
, &s
, p
);
121 __sub (&mptwo
, &c
, &t1
, p
);
122 __mul (&t1
, &c
, &t2
, p
);
123 __add (&t2
, &t2
, &c
, p
);
125 __sub (&mpone
, &c
, y
, p
);
129 /* Receive double x and two double results of sin(x) and return result which is
130 more accurate, computing sin(x) with multi precision routine c32. */
133 __sin32 (double x
, double res
, double res1
)
138 __dbl_mp (res
, &a
, p
);
139 __dbl_mp (0.5 * (res1
- res
), &b
, p
);
140 __add (&a
, &b
, &c
, p
);
143 __sub (&hp
, &c
, &a
, p
);
144 __c32 (&a
, &b
, &c
, p
);
147 __c32 (&c
, &a
, &b
, p
); /* b=sin(0.5*(res+res1)) */
148 __dbl_mp (x
, &c
, p
); /* c = x */
149 __sub (&b
, &c
, &a
, p
);
150 /* if a > 0 return min (res, res1), otherwise return max (res, res1). */
151 if ((a
.d
[0] > 0 && res
>= res1
) || (a
.d
[0] <= 0 && res
<= res1
))
153 LIBC_PROBE (slowasin
, 2, &res
, &x
);
157 /* Receive double x and two double results of cos(x) and return result which is
158 more accurate, computing cos(x) with multi precision routine c32. */
161 __cos32 (double x
, double res
, double res1
)
166 __dbl_mp (res
, &a
, p
);
167 __dbl_mp (0.5 * (res1
- res
), &b
, p
);
168 __add (&a
, &b
, &c
, p
);
171 __sub (&pi
, &c
, &a
, p
);
172 __c32 (&a
, &b
, &c
, p
);
177 __sub (&hp
, &c
, &a
, p
);
178 __c32 (&a
, &c
, &b
, p
);
181 __c32 (&c
, &b
, &a
, p
); /* b=cos(0.5*(res+res1)) */
182 __dbl_mp (x
, &c
, p
); /* c = x */
183 __sub (&b
, &c
, &a
, p
);
184 /* if a > 0 return max (res, res1), otherwise return min (res, res1). */
185 if ((a
.d
[0] > 0 && res
<= res1
) || (a
.d
[0] <= 0 && res
>= res1
))
187 LIBC_PROBE (slowacos
, 2, &res
, &x
);
191 /* Compute sin() of double-length number (X + DX) as Multi Precision number and
192 return result as double. If REDUCE_RANGE is true, X is assumed to be the
193 original input and DX is ignored. */
196 __mpsin (double x
, double dx
, bool reduce_range
)
205 n
= __mpranred (x
, &a
, p
); /* n is 0, 1, 2 or 3. */
206 __c32 (&a
, &c
, &s
, p
);
212 __dbl_mp (dx
, &c
, p
);
213 __add (&b
, &c
, &a
, p
);
216 __sub (&hp
, &a
, &b
, p
);
217 __c32 (&b
, &s
, &c
, p
);
220 __c32 (&a
, &c
, &s
, p
); /* b = sin(x+dx) */
223 /* Convert result based on which quarter of unit circle y is in. */
227 __mp_dbl (&c
, &y
, p
);
231 __mp_dbl (&c
, &y
, p
);
236 __mp_dbl (&s
, &y
, p
);
240 /* Quadrant not set, so the result must be sin (X + DX), which is also in
244 __mp_dbl (&s
, &y
, p
);
246 LIBC_PROBE (slowsin
, 3, &x
, &dx
, &y
);
250 /* Compute cos() of double-length number (X + DX) as Multi Precision number and
251 return result as double. If REDUCE_RANGE is true, X is assumed to be the
252 original input and DX is ignored. */
255 __mpcos (double x
, double dx
, bool reduce_range
)
264 n
= __mpranred (x
, &a
, p
); /* n is 0, 1, 2 or 3. */
265 __c32 (&a
, &c
, &s
, p
);
271 __dbl_mp (dx
, &c
, p
);
272 __add (&b
, &c
, &a
, p
);
275 __sub (&hp
, &a
, &b
, p
);
276 __c32 (&b
, &s
, &c
, p
);
279 __c32 (&a
, &c
, &s
, p
); /* a = cos(x+dx) */
282 /* Convert result based on which quarter of unit circle y is in. */
286 __mp_dbl (&s
, &y
, p
);
291 __mp_dbl (&s
, &y
, p
);
295 __mp_dbl (&c
, &y
, p
);
299 /* Quadrant not set, so the result must be cos (X + DX), which is also
303 __mp_dbl (&c
, &y
, p
);
305 LIBC_PROBE (slowcos
, 3, &x
, &dx
, &y
);
309 /* Perform range reduction of a double number x into multi precision number y,
310 such that y = x - n * pi / 2, abs (y) < pi / 4, n = 0, +-1, +-2, ...
311 Return int which indicates in which quarter of circle x is. */
314 __mpranred (double x
, mp_no
*y
, int p
)
321 if (ABS (x
) < 2.8e14
)
323 t
= (x
* hpinv
.d
+ toint
.d
);
326 n
= v
.i
[LOW_HALF
] & 3;
327 __dbl_mp (xn
, &a
, p
);
328 __mul (&a
, &hp
, &b
, p
);
330 __sub (&c
, &b
, y
, p
);
335 /* If x is very big more precision required. */
343 for (i
= 0; i
< p
; i
++)
344 b
.d
[i
+ 1] = toverp
[i
+ k
];
345 __mul (&a
, &b
, &c
, p
);
347 for (i
= 1; i
<= p
- c
.e
; i
++)
348 c
.d
[i
] = c
.d
[i
+ c
.e
];
349 for (i
= p
+ 1 - c
.e
; i
<= p
; i
++)
352 if (c
.d
[1] >= HALFRAD
)
355 __sub (&c
, &mpone
, &b
, p
);
356 __mul (&b
, &hp
, y
, p
);
359 __mul (&c
, &hp
, y
, p
);