]>
Commit | Line | Data |
---|---|---|
f7eac6eb | 1 | /* |
e4d82761 | 2 | * IBM Accurate Mathematical Library |
aeb25823 | 3 | * written by International Business Machines Corp. |
568035b7 | 4 | * Copyright (C) 2001-2013 Free Software Foundation, Inc. |
f7eac6eb | 5 | * |
e4d82761 UD |
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 | |
cc7375ce | 8 | * the Free Software Foundation; either version 2.1 of the License, or |
e4d82761 | 9 | * (at your option) any later version. |
f7eac6eb | 10 | * |
e4d82761 UD |
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 | |
c6c6dd48 | 14 | * GNU Lesser General Public License for more details. |
f7eac6eb | 15 | * |
e4d82761 | 16 | * You should have received a copy of the GNU Lesser General Public License |
59ba27a6 | 17 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
f7eac6eb | 18 | */ |
e4d82761 UD |
19 | /****************************************************************************/ |
20 | /* */ | |
21 | /* MODULE_NAME:usncs.c */ | |
22 | /* */ | |
23 | /* FUNCTIONS: usin */ | |
24 | /* ucos */ | |
25 | /* slow */ | |
26 | /* slow1 */ | |
27 | /* slow2 */ | |
28 | /* sloww */ | |
29 | /* sloww1 */ | |
30 | /* sloww2 */ | |
31 | /* bsloww */ | |
32 | /* bsloww1 */ | |
33 | /* bsloww2 */ | |
34 | /* cslow2 */ | |
35 | /* csloww */ | |
36 | /* csloww1 */ | |
37 | /* csloww2 */ | |
38 | /* FILES NEEDED: dla.h endian.h mpa.h mydefs.h usncs.h */ | |
39 | /* branred.c sincos32.c dosincos.c mpa.c */ | |
40 | /* sincos.tbl */ | |
41 | /* */ | |
42 | /* An ultimate sin and routine. Given an IEEE double machine number x */ | |
43 | /* it computes the correctly rounded (to nearest) value of sin(x) or cos(x) */ | |
44 | /* Assumption: Machine arithmetic operations are performed in */ | |
45 | /* round to nearest mode of IEEE 754 standard. */ | |
46 | /* */ | |
47 | /****************************************************************************/ | |
f7eac6eb | 48 | |
f7eac6eb | 49 | |
0c59a196 | 50 | #include <errno.h> |
e4d82761 UD |
51 | #include "endian.h" |
52 | #include "mydefs.h" | |
53 | #include "usncs.h" | |
54 | #include "MathLib.h" | |
1ed0291c | 55 | #include <math_private.h> |
804360ed | 56 | #include <fenv.h> |
e4d82761 | 57 | |
4aafb73c | 58 | /* Helper macros to compute sin of the input values. */ |
196f7f5d | 59 | #define POLYNOMIAL2(xx) ((((s5 * (xx) + s4) * (xx) + s3) * (xx) + s2) * (xx)) |
4aafb73c | 60 | |
196f7f5d | 61 | #define POLYNOMIAL(xx) (POLYNOMIAL2 (xx) + s1) |
4aafb73c SP |
62 | |
63 | /* The computed polynomial is a variation of the Taylor series expansion for | |
64 | sin(a): | |
65 | ||
66 | a - a^3/3! + a^5/5! - a^7/7! + a^9/9! + (1 - a^2) * da / 2 | |
67 | ||
68 | The constants s1, s2, s3, etc. are pre-computed values of 1/3!, 1/5! and so | |
69 | on. The result is returned to LHS and correction in COR. */ | |
70 | #define TAYLOR_SINCOS(xx, a, da, cor) \ | |
71 | ({ \ | |
72 | double t = ((POLYNOMIAL (xx) * (a) - 0.5 * (da)) * (xx) + (da)); \ | |
73 | double res = (a) + t; \ | |
74 | (cor) = ((a) - res) + t; \ | |
75 | res; \ | |
76 | }) | |
77 | ||
78 | /* This is again a variation of the Taylor series expansion with the term | |
79 | x^3/3! expanded into the following for better accuracy: | |
80 | ||
81 | bb * x ^ 3 + 3 * aa * x * x1 * x2 + aa * x1 ^ 3 + aa * x2 ^ 3 | |
82 | ||
83 | The correction term is dx and bb + aa = -1/3! | |
84 | */ | |
85 | #define TAYLOR_SLOW(x0, dx, cor) \ | |
86 | ({ \ | |
87 | static const double th2_36 = 206158430208.0; /* 1.5*2**37 */ \ | |
88 | double xx = (x0) * (x0); \ | |
89 | double x1 = ((x0) + th2_36) - th2_36; \ | |
196f7f5d | 90 | double y = aa * x1 * x1 * x1; \ |
4aafb73c SP |
91 | double r = (x0) + y; \ |
92 | double x2 = ((x0) - x1) + (dx); \ | |
196f7f5d SP |
93 | double t = (((POLYNOMIAL2 (xx) + bb) * xx + 3.0 * aa * x1 * x2) \ |
94 | * (x0) + aa * x2 * x2 * x2 + (dx)); \ | |
4aafb73c SP |
95 | t = (((x0) - r) + y) + t; \ |
96 | double res = r + t; \ | |
97 | (cor) = (r - res) + t; \ | |
98 | res; \ | |
99 | }) | |
100 | ||
b348e1e3 SP |
101 | #define SINCOS_TABLE_LOOKUP(u, sn, ssn, cs, ccs) \ |
102 | ({ \ | |
103 | int4 k = u.i[LOW_HALF] << 2; \ | |
104 | sn = __sincostab.x[k]; \ | |
105 | ssn = __sincostab.x[k + 1]; \ | |
106 | cs = __sincostab.x[k + 2]; \ | |
107 | ccs = __sincostab.x[k + 3]; \ | |
108 | }) | |
109 | ||
31d3cc00 UD |
110 | #ifndef SECTION |
111 | # define SECTION | |
112 | #endif | |
113 | ||
af968f62 UD |
114 | extern const union |
115 | { | |
116 | int4 i[880]; | |
117 | double x[440]; | |
118 | } __sincostab attribute_hidden; | |
119 | ||
e4d82761 | 120 | static const double |
6dbe713d SP |
121 | sn3 = -1.66666666666664880952546298448555E-01, |
122 | sn5 = 8.33333214285722277379541354343671E-03, | |
123 | cs2 = 4.99999999999999999999950396842453E-01, | |
124 | cs4 = -4.16666666666664434524222570944589E-02, | |
125 | cs6 = 1.38888874007937613028114285595617E-03; | |
126 | ||
7a74607f SP |
127 | static const double t22 = 0x1.8p22; |
128 | ||
6dbe713d SP |
129 | void __dubsin (double x, double dx, double w[]); |
130 | void __docos (double x, double dx, double w[]); | |
09544cbc SP |
131 | double __mpsin (double x, double dx, bool reduce_range); |
132 | double __mpcos (double x, double dx, bool reduce_range); | |
6dbe713d SP |
133 | static double slow (double x); |
134 | static double slow1 (double x); | |
135 | static double slow2 (double x); | |
136 | static double sloww (double x, double dx, double orig); | |
137 | static double sloww1 (double x, double dx, double orig); | |
138 | static double sloww2 (double x, double dx, double orig, int n); | |
139 | static double bsloww (double x, double dx, double orig, int n); | |
140 | static double bsloww1 (double x, double dx, double orig, int n); | |
141 | static double bsloww2 (double x, double dx, double orig, int n); | |
142 | int __branred (double x, double *a, double *aa); | |
143 | static double cslow2 (double x); | |
144 | static double csloww (double x, double dx, double orig); | |
145 | static double csloww1 (double x, double dx, double orig); | |
146 | static double csloww2 (double x, double dx, double orig, int n); | |
147 | ||
6cce25f8 SP |
148 | /* Reduce range of X and compute sin of a + da. K is the amount by which to |
149 | rotate the quadrants. This allows us to use the same routine to compute cos | |
150 | by simply rotating the quadrants by 1. */ | |
151 | static inline double | |
152 | __always_inline | |
153 | reduce_and_compute (double x, double a, double da, unsigned int k) | |
154 | { | |
155 | double retval = 0; | |
156 | unsigned int n = __branred (x, &a, &da); | |
157 | k = (n + k) % 4; | |
158 | switch (k) | |
159 | { | |
160 | case 0: | |
161 | if (a * a < 0.01588) | |
162 | retval = bsloww (a, da, x, n); | |
163 | else | |
164 | retval = bsloww1 (a, da, x, n); | |
165 | break; | |
166 | case 2: | |
167 | if (a * a < 0.01588) | |
168 | retval = bsloww (-a, -da, x, n); | |
169 | else | |
170 | retval = bsloww1 (-a, -da, x, n); | |
171 | break; | |
172 | ||
173 | case 1: | |
174 | case 3: | |
175 | retval = bsloww2 (a, da, x, n); | |
176 | break; | |
177 | } | |
178 | return retval; | |
179 | } | |
180 | ||
e4d82761 UD |
181 | /*******************************************************************/ |
182 | /* An ultimate sin routine. Given an IEEE double machine number x */ | |
183 | /* it computes the correctly rounded (to nearest) value of sin(x) */ | |
184 | /*******************************************************************/ | |
31d3cc00 UD |
185 | double |
186 | SECTION | |
6dbe713d SP |
187 | __sin (double x) |
188 | { | |
189 | double xx, res, t, cor, y, s, c, sn, ssn, cs, ccs, xn, a, da, db, eps, xn1, | |
190 | xn2; | |
191 | mynumber u, v; | |
192 | int4 k, m, n; | |
193 | double retval = 0; | |
194 | ||
195 | SET_RESTORE_ROUND_53BIT (FE_TONEAREST); | |
196 | ||
197 | u.x = x; | |
198 | m = u.i[HIGH_HALF]; | |
199 | k = 0x7fffffff & m; /* no sign */ | |
200 | if (k < 0x3e500000) /* if x->0 =>sin(x)=x */ | |
5eea0404 | 201 | retval = x; |
e4d82761 | 202 | /*---------------------------- 2^-26 < |x|< 0.25 ----------------------*/ |
6dbe713d SP |
203 | else if (k < 0x3fd00000) |
204 | { | |
205 | xx = x * x; | |
4aafb73c SP |
206 | /* Taylor series. */ |
207 | t = POLYNOMIAL (xx) * (xx * x); | |
6dbe713d SP |
208 | res = x + t; |
209 | cor = (x - res) + t; | |
210 | retval = (res == res + 1.07 * cor) ? res : slow (x); | |
6dbe713d | 211 | } /* else if (k < 0x3fd00000) */ |
e4d82761 | 212 | /*---------------------------- 0.25<|x|< 0.855469---------------------- */ |
6dbe713d SP |
213 | else if (k < 0x3feb6000) |
214 | { | |
196f7f5d SP |
215 | u.x = (m > 0) ? big + x : big - x; |
216 | y = (m > 0) ? x - (u.x - big) : x + (u.x - big); | |
6dbe713d SP |
217 | xx = y * y; |
218 | s = y + y * xx * (sn3 + xx * sn5); | |
219 | c = xx * (cs2 + xx * (cs4 + xx * cs6)); | |
b348e1e3 SP |
220 | SINCOS_TABLE_LOOKUP (u, sn, ssn, cs, ccs); |
221 | if (m <= 0) | |
222 | { | |
223 | sn = -sn; | |
224 | ssn = -ssn; | |
225 | } | |
6dbe713d SP |
226 | cor = (ssn + s * ccs - sn * c) + cs * s; |
227 | res = sn + cor; | |
228 | cor = (sn - res) + cor; | |
229 | retval = (res == res + 1.096 * cor) ? res : slow1 (x); | |
6dbe713d | 230 | } /* else if (k < 0x3feb6000) */ |
e4d82761 UD |
231 | |
232 | /*----------------------- 0.855469 <|x|<2.426265 ----------------------*/ | |
6dbe713d SP |
233 | else if (k < 0x400368fd) |
234 | { | |
235 | ||
196f7f5d | 236 | y = (m > 0) ? hp0 - x : hp0 + x; |
6dbe713d SP |
237 | if (y >= 0) |
238 | { | |
196f7f5d SP |
239 | u.x = big + y; |
240 | y = (y - (u.x - big)) + hp1; | |
6dbe713d SP |
241 | } |
242 | else | |
243 | { | |
196f7f5d SP |
244 | u.x = big - y; |
245 | y = (-hp1) - (y + (u.x - big)); | |
6dbe713d SP |
246 | } |
247 | xx = y * y; | |
248 | s = y + y * xx * (sn3 + xx * sn5); | |
249 | c = xx * (cs2 + xx * (cs4 + xx * cs6)); | |
b348e1e3 | 250 | SINCOS_TABLE_LOOKUP (u, sn, ssn, cs, ccs); |
6dbe713d SP |
251 | cor = (ccs - s * ssn - cs * c) - sn * s; |
252 | res = cs + cor; | |
253 | cor = (cs - res) + cor; | |
254 | retval = (res == res + 1.020 * cor) ? ((m > 0) ? res : -res) : slow2 (x); | |
6dbe713d | 255 | } /* else if (k < 0x400368fd) */ |
e4d82761 UD |
256 | |
257 | /*-------------------------- 2.426265<|x|< 105414350 ----------------------*/ | |
6dbe713d SP |
258 | else if (k < 0x419921FB) |
259 | { | |
196f7f5d SP |
260 | t = (x * hpinv + toint); |
261 | xn = t - toint; | |
6dbe713d | 262 | v.x = t; |
196f7f5d | 263 | y = (x - xn * mp1) - xn * mp2; |
6dbe713d | 264 | n = v.i[LOW_HALF] & 3; |
196f7f5d | 265 | da = xn * mp3; |
6dbe713d SP |
266 | a = y - da; |
267 | da = (y - a) - da; | |
268 | eps = ABS (x) * 1.2e-30; | |
269 | ||
270 | switch (n) | |
271 | { /* quarter of unit circle */ | |
272 | case 0: | |
273 | case 2: | |
274 | xx = a * a; | |
275 | if (n) | |
276 | { | |
277 | a = -a; | |
278 | da = -da; | |
279 | } | |
280 | if (xx < 0.01588) | |
281 | { | |
4aafb73c SP |
282 | /* Taylor series. */ |
283 | res = TAYLOR_SINCOS (xx, a, da, cor); | |
6dbe713d SP |
284 | cor = (cor > 0) ? 1.02 * cor + eps : 1.02 * cor - eps; |
285 | retval = (res == res + cor) ? res : sloww (a, da, x); | |
f7eac6eb | 286 | } |
6dbe713d SP |
287 | else |
288 | { | |
289 | if (a > 0) | |
290 | { | |
291 | m = 1; | |
292 | t = a; | |
293 | db = da; | |
294 | } | |
e4d82761 | 295 | else |
6dbe713d SP |
296 | { |
297 | m = 0; | |
298 | t = -a; | |
299 | db = -da; | |
300 | } | |
196f7f5d SP |
301 | u.x = big + t; |
302 | y = t - (u.x - big); | |
6dbe713d SP |
303 | xx = y * y; |
304 | s = y + (db + y * xx * (sn3 + xx * sn5)); | |
305 | c = y * db + xx * (cs2 + xx * (cs4 + xx * cs6)); | |
b348e1e3 | 306 | SINCOS_TABLE_LOOKUP (u, sn, ssn, cs, ccs); |
6dbe713d SP |
307 | cor = (ssn + s * ccs - sn * c) + cs * s; |
308 | res = sn + cor; | |
309 | cor = (sn - res) + cor; | |
310 | cor = (cor > 0) ? 1.035 * cor + eps : 1.035 * cor - eps; | |
311 | retval = ((res == res + cor) ? ((m) ? res : -res) | |
312 | : sloww1 (a, da, x)); | |
e4d82761 | 313 | } |
6dbe713d SP |
314 | break; |
315 | ||
316 | case 1: | |
317 | case 3: | |
318 | if (a < 0) | |
319 | { | |
320 | a = -a; | |
321 | da = -da; | |
322 | } | |
196f7f5d SP |
323 | u.x = big + a; |
324 | y = a - (u.x - big) + da; | |
6dbe713d | 325 | xx = y * y; |
b348e1e3 | 326 | SINCOS_TABLE_LOOKUP (u, sn, ssn, cs, ccs); |
6dbe713d SP |
327 | s = y + y * xx * (sn3 + xx * sn5); |
328 | c = xx * (cs2 + xx * (cs4 + xx * cs6)); | |
329 | cor = (ccs - s * ssn - cs * c) - sn * s; | |
330 | res = cs + cor; | |
331 | cor = (cs - res) + cor; | |
332 | cor = (cor > 0) ? 1.025 * cor + eps : 1.025 * cor - eps; | |
333 | retval = ((res == res + cor) ? ((n & 2) ? -res : res) | |
334 | : sloww2 (a, da, x, n)); | |
6dbe713d SP |
335 | break; |
336 | } | |
6dbe713d | 337 | } /* else if (k < 0x419921FB ) */ |
e4d82761 UD |
338 | |
339 | /*---------------------105414350 <|x|< 281474976710656 --------------------*/ | |
6dbe713d SP |
340 | else if (k < 0x42F00000) |
341 | { | |
196f7f5d SP |
342 | t = (x * hpinv + toint); |
343 | xn = t - toint; | |
6dbe713d SP |
344 | v.x = t; |
345 | xn1 = (xn + 8.0e22) - 8.0e22; | |
346 | xn2 = xn - xn1; | |
196f7f5d | 347 | y = ((((x - xn1 * mp1) - xn1 * mp2) - xn2 * mp1) - xn2 * mp2); |
6dbe713d | 348 | n = v.i[LOW_HALF] & 3; |
196f7f5d | 349 | da = xn1 * pp3; |
6dbe713d SP |
350 | t = y - da; |
351 | da = (y - t) - da; | |
196f7f5d | 352 | da = (da - xn2 * pp3) - xn * pp4; |
6dbe713d SP |
353 | a = t + da; |
354 | da = (t - a) + da; | |
355 | eps = 1.0e-24; | |
356 | ||
357 | switch (n) | |
358 | { | |
359 | case 0: | |
360 | case 2: | |
361 | xx = a * a; | |
362 | if (n) | |
363 | { | |
364 | a = -a; | |
365 | da = -da; | |
366 | } | |
367 | if (xx < 0.01588) | |
368 | { | |
4aafb73c SP |
369 | /* Taylor series. */ |
370 | res = TAYLOR_SINCOS (xx, a, da, cor); | |
6dbe713d SP |
371 | cor = (cor > 0) ? 1.02 * cor + eps : 1.02 * cor - eps; |
372 | retval = (res == res + cor) ? res : bsloww (a, da, x, n); | |
e4d82761 | 373 | } |
6dbe713d SP |
374 | else |
375 | { | |
376 | if (a > 0) | |
377 | { | |
378 | m = 1; | |
379 | t = a; | |
380 | db = da; | |
381 | } | |
382 | else | |
383 | { | |
384 | m = 0; | |
385 | t = -a; | |
386 | db = -da; | |
387 | } | |
196f7f5d SP |
388 | u.x = big + t; |
389 | y = t - (u.x - big); | |
6dbe713d SP |
390 | xx = y * y; |
391 | s = y + (db + y * xx * (sn3 + xx * sn5)); | |
392 | c = y * db + xx * (cs2 + xx * (cs4 + xx * cs6)); | |
b348e1e3 | 393 | SINCOS_TABLE_LOOKUP (u, sn, ssn, cs, ccs); |
6dbe713d SP |
394 | cor = (ssn + s * ccs - sn * c) + cs * s; |
395 | res = sn + cor; | |
396 | cor = (sn - res) + cor; | |
397 | cor = (cor > 0) ? 1.035 * cor + eps : 1.035 * cor - eps; | |
398 | retval = ((res == res + cor) ? ((m) ? res : -res) | |
399 | : bsloww1 (a, da, x, n)); | |
6dbe713d SP |
400 | } |
401 | break; | |
402 | ||
403 | case 1: | |
404 | case 3: | |
405 | if (a < 0) | |
406 | { | |
407 | a = -a; | |
408 | da = -da; | |
409 | } | |
196f7f5d SP |
410 | u.x = big + a; |
411 | y = a - (u.x - big) + da; | |
6dbe713d | 412 | xx = y * y; |
b348e1e3 | 413 | SINCOS_TABLE_LOOKUP (u, sn, ssn, cs, ccs); |
6dbe713d SP |
414 | s = y + y * xx * (sn3 + xx * sn5); |
415 | c = xx * (cs2 + xx * (cs4 + xx * cs6)); | |
416 | cor = (ccs - s * ssn - cs * c) - sn * s; | |
417 | res = cs + cor; | |
418 | cor = (cs - res) + cor; | |
419 | cor = (cor > 0) ? 1.025 * cor + eps : 1.025 * cor - eps; | |
420 | retval = ((res == res + cor) ? ((n & 2) ? -res : res) | |
421 | : bsloww2 (a, da, x, n)); | |
6dbe713d SP |
422 | break; |
423 | } | |
424 | } /* else if (k < 0x42F00000 ) */ | |
e4d82761 UD |
425 | |
426 | /* -----------------281474976710656 <|x| <2^1024----------------------------*/ | |
6dbe713d | 427 | else if (k < 0x7ff00000) |
6cce25f8 | 428 | retval = reduce_and_compute (x, a, da, 0); |
6dbe713d SP |
429 | |
430 | /*--------------------- |x| > 2^1024 ----------------------------------*/ | |
431 | else | |
432 | { | |
433 | if (k == 0x7ff00000 && u.i[LOW_HALF] == 0) | |
434 | __set_errno (EDOM); | |
435 | retval = x / x; | |
6dbe713d | 436 | } |
804360ed | 437 | |
6dbe713d | 438 | return retval; |
e4d82761 UD |
439 | } |
440 | ||
441 | ||
442 | /*******************************************************************/ | |
443 | /* An ultimate cos routine. Given an IEEE double machine number x */ | |
444 | /* it computes the correctly rounded (to nearest) value of cos(x) */ | |
445 | /*******************************************************************/ | |
446 | ||
31d3cc00 UD |
447 | double |
448 | SECTION | |
6dbe713d | 449 | __cos (double x) |
e4d82761 | 450 | { |
6dbe713d SP |
451 | double y, xx, res, t, cor, s, c, sn, ssn, cs, ccs, xn, a, da, db, eps, xn1, |
452 | xn2; | |
453 | mynumber u, v; | |
454 | int4 k, m, n; | |
e4d82761 | 455 | |
804360ed JM |
456 | double retval = 0; |
457 | ||
eb92c487 | 458 | SET_RESTORE_ROUND_53BIT (FE_TONEAREST); |
804360ed | 459 | |
e4d82761 UD |
460 | u.x = x; |
461 | m = u.i[HIGH_HALF]; | |
6dbe713d | 462 | k = 0x7fffffff & m; |
e4d82761 | 463 | |
5eea0404 | 464 | /* |x|<2^-27 => cos(x)=1 */ |
6dbe713d | 465 | if (k < 0x3e400000) |
5eea0404 | 466 | retval = 1.0; |
6dbe713d SP |
467 | |
468 | else if (k < 0x3feb6000) | |
469 | { /* 2^-27 < |x| < 0.855469 */ | |
470 | y = ABS (x); | |
196f7f5d SP |
471 | u.x = big + y; |
472 | y = y - (u.x - big); | |
6dbe713d SP |
473 | xx = y * y; |
474 | s = y + y * xx * (sn3 + xx * sn5); | |
475 | c = xx * (cs2 + xx * (cs4 + xx * cs6)); | |
b348e1e3 | 476 | SINCOS_TABLE_LOOKUP (u, sn, ssn, cs, ccs); |
6dbe713d SP |
477 | cor = (ccs - s * ssn - cs * c) - sn * s; |
478 | res = cs + cor; | |
479 | cor = (cs - res) + cor; | |
480 | retval = (res == res + 1.020 * cor) ? res : cslow2 (x); | |
6dbe713d SP |
481 | } /* else if (k < 0x3feb6000) */ |
482 | ||
483 | else if (k < 0x400368fd) | |
484 | { /* 0.855469 <|x|<2.426265 */ ; | |
196f7f5d SP |
485 | y = hp0 - ABS (x); |
486 | a = y + hp1; | |
487 | da = (y - a) + hp1; | |
6dbe713d SP |
488 | xx = a * a; |
489 | if (xx < 0.01588) | |
490 | { | |
4aafb73c | 491 | res = TAYLOR_SINCOS (xx, a, da, cor); |
6dbe713d SP |
492 | cor = (cor > 0) ? 1.02 * cor + 1.0e-31 : 1.02 * cor - 1.0e-31; |
493 | retval = (res == res + cor) ? res : csloww (a, da, x); | |
6dbe713d SP |
494 | } |
495 | else | |
496 | { | |
497 | if (a > 0) | |
498 | { | |
499 | m = 1; | |
500 | t = a; | |
501 | db = da; | |
502 | } | |
503 | else | |
504 | { | |
505 | m = 0; | |
506 | t = -a; | |
507 | db = -da; | |
508 | } | |
196f7f5d SP |
509 | u.x = big + t; |
510 | y = t - (u.x - big); | |
6dbe713d SP |
511 | xx = y * y; |
512 | s = y + (db + y * xx * (sn3 + xx * sn5)); | |
513 | c = y * db + xx * (cs2 + xx * (cs4 + xx * cs6)); | |
b348e1e3 | 514 | SINCOS_TABLE_LOOKUP (u, sn, ssn, cs, ccs); |
6dbe713d SP |
515 | cor = (ssn + s * ccs - sn * c) + cs * s; |
516 | res = sn + cor; | |
517 | cor = (sn - res) + cor; | |
518 | cor = (cor > 0) ? 1.035 * cor + 1.0e-31 : 1.035 * cor - 1.0e-31; | |
519 | retval = ((res == res + cor) ? ((m) ? res : -res) | |
520 | : csloww1 (a, da, x)); | |
6dbe713d | 521 | } |
e4d82761 | 522 | |
6dbe713d | 523 | } /* else if (k < 0x400368fd) */ |
e4d82761 | 524 | |
e4d82761 | 525 | |
6dbe713d SP |
526 | else if (k < 0x419921FB) |
527 | { /* 2.426265<|x|< 105414350 */ | |
196f7f5d SP |
528 | t = (x * hpinv + toint); |
529 | xn = t - toint; | |
6dbe713d | 530 | v.x = t; |
196f7f5d | 531 | y = (x - xn * mp1) - xn * mp2; |
6dbe713d | 532 | n = v.i[LOW_HALF] & 3; |
196f7f5d | 533 | da = xn * mp3; |
6dbe713d SP |
534 | a = y - da; |
535 | da = (y - a) - da; | |
536 | eps = ABS (x) * 1.2e-30; | |
537 | ||
538 | switch (n) | |
539 | { | |
540 | case 1: | |
541 | case 3: | |
542 | xx = a * a; | |
543 | if (n == 1) | |
544 | { | |
545 | a = -a; | |
546 | da = -da; | |
547 | } | |
548 | if (xx < 0.01588) | |
549 | { | |
4aafb73c | 550 | res = TAYLOR_SINCOS (xx, a, da, cor); |
6dbe713d SP |
551 | cor = (cor > 0) ? 1.02 * cor + eps : 1.02 * cor - eps; |
552 | retval = (res == res + cor) ? res : csloww (a, da, x); | |
6dbe713d SP |
553 | } |
554 | else | |
555 | { | |
556 | if (a > 0) | |
557 | { | |
558 | m = 1; | |
559 | t = a; | |
560 | db = da; | |
561 | } | |
562 | else | |
563 | { | |
564 | m = 0; | |
565 | t = -a; | |
566 | db = -da; | |
567 | } | |
196f7f5d SP |
568 | u.x = big + t; |
569 | y = t - (u.x - big); | |
6dbe713d SP |
570 | xx = y * y; |
571 | s = y + (db + y * xx * (sn3 + xx * sn5)); | |
572 | c = y * db + xx * (cs2 + xx * (cs4 + xx * cs6)); | |
b348e1e3 | 573 | SINCOS_TABLE_LOOKUP (u, sn, ssn, cs, ccs); |
6dbe713d SP |
574 | cor = (ssn + s * ccs - sn * c) + cs * s; |
575 | res = sn + cor; | |
576 | cor = (sn - res) + cor; | |
577 | cor = (cor > 0) ? 1.035 * cor + eps : 1.035 * cor - eps; | |
578 | retval = ((res == res + cor) ? ((m) ? res : -res) | |
579 | : csloww1 (a, da, x)); | |
6dbe713d SP |
580 | } |
581 | break; | |
582 | ||
583 | case 0: | |
584 | case 2: | |
585 | if (a < 0) | |
586 | { | |
587 | a = -a; | |
588 | da = -da; | |
589 | } | |
196f7f5d SP |
590 | u.x = big + a; |
591 | y = a - (u.x - big) + da; | |
6dbe713d | 592 | xx = y * y; |
b348e1e3 | 593 | SINCOS_TABLE_LOOKUP (u, sn, ssn, cs, ccs); |
6dbe713d SP |
594 | s = y + y * xx * (sn3 + xx * sn5); |
595 | c = xx * (cs2 + xx * (cs4 + xx * cs6)); | |
596 | cor = (ccs - s * ssn - cs * c) - sn * s; | |
597 | res = cs + cor; | |
598 | cor = (cs - res) + cor; | |
599 | cor = (cor > 0) ? 1.025 * cor + eps : 1.025 * cor - eps; | |
600 | retval = ((res == res + cor) ? ((n) ? -res : res) | |
601 | : csloww2 (a, da, x, n)); | |
6dbe713d SP |
602 | break; |
603 | } | |
604 | } /* else if (k < 0x419921FB ) */ | |
e4d82761 | 605 | |
6dbe713d SP |
606 | else if (k < 0x42F00000) |
607 | { | |
196f7f5d SP |
608 | t = (x * hpinv + toint); |
609 | xn = t - toint; | |
6dbe713d SP |
610 | v.x = t; |
611 | xn1 = (xn + 8.0e22) - 8.0e22; | |
612 | xn2 = xn - xn1; | |
196f7f5d | 613 | y = ((((x - xn1 * mp1) - xn1 * mp2) - xn2 * mp1) - xn2 * mp2); |
6dbe713d | 614 | n = v.i[LOW_HALF] & 3; |
196f7f5d | 615 | da = xn1 * pp3; |
6dbe713d SP |
616 | t = y - da; |
617 | da = (y - t) - da; | |
196f7f5d | 618 | da = (da - xn2 * pp3) - xn * pp4; |
6dbe713d SP |
619 | a = t + da; |
620 | da = (t - a) + da; | |
621 | eps = 1.0e-24; | |
622 | ||
623 | switch (n) | |
624 | { | |
625 | case 1: | |
626 | case 3: | |
627 | xx = a * a; | |
628 | if (n == 1) | |
629 | { | |
630 | a = -a; | |
631 | da = -da; | |
632 | } | |
633 | if (xx < 0.01588) | |
634 | { | |
4aafb73c | 635 | res = TAYLOR_SINCOS (xx, a, da, cor); |
6dbe713d SP |
636 | cor = (cor > 0) ? 1.02 * cor + eps : 1.02 * cor - eps; |
637 | retval = (res == res + cor) ? res : bsloww (a, da, x, n); | |
6dbe713d SP |
638 | } |
639 | else | |
640 | { | |
641 | if (a > 0) | |
642 | { | |
643 | m = 1; | |
644 | t = a; | |
645 | db = da; | |
646 | } | |
647 | else | |
648 | { | |
649 | m = 0; | |
650 | t = -a; | |
651 | db = -da; | |
652 | } | |
196f7f5d SP |
653 | u.x = big + t; |
654 | y = t - (u.x - big); | |
6dbe713d SP |
655 | xx = y * y; |
656 | s = y + (db + y * xx * (sn3 + xx * sn5)); | |
657 | c = y * db + xx * (cs2 + xx * (cs4 + xx * cs6)); | |
b348e1e3 | 658 | SINCOS_TABLE_LOOKUP (u, sn, ssn, cs, ccs); |
6dbe713d SP |
659 | cor = (ssn + s * ccs - sn * c) + cs * s; |
660 | res = sn + cor; | |
661 | cor = (sn - res) + cor; | |
662 | cor = (cor > 0) ? 1.035 * cor + eps : 1.035 * cor - eps; | |
663 | retval = ((res == res + cor) ? ((m) ? res : -res) | |
664 | : bsloww1 (a, da, x, n)); | |
6dbe713d SP |
665 | } |
666 | break; | |
667 | ||
668 | case 0: | |
669 | case 2: | |
670 | if (a < 0) | |
671 | { | |
672 | a = -a; | |
673 | da = -da; | |
674 | } | |
196f7f5d SP |
675 | u.x = big + a; |
676 | y = a - (u.x - big) + da; | |
6dbe713d | 677 | xx = y * y; |
b348e1e3 | 678 | SINCOS_TABLE_LOOKUP (u, sn, ssn, cs, ccs); |
6dbe713d SP |
679 | s = y + y * xx * (sn3 + xx * sn5); |
680 | c = xx * (cs2 + xx * (cs4 + xx * cs6)); | |
681 | cor = (ccs - s * ssn - cs * c) - sn * s; | |
682 | res = cs + cor; | |
683 | cor = (cs - res) + cor; | |
684 | cor = (cor > 0) ? 1.025 * cor + eps : 1.025 * cor - eps; | |
685 | retval = ((res == res + cor) ? ((n) ? -res : res) | |
686 | : bsloww2 (a, da, x, n)); | |
6dbe713d SP |
687 | break; |
688 | } | |
689 | } /* else if (k < 0x42F00000 ) */ | |
690 | ||
6cce25f8 | 691 | /* 281474976710656 <|x| <2^1024 */ |
6dbe713d | 692 | else if (k < 0x7ff00000) |
6cce25f8 | 693 | retval = reduce_and_compute (x, a, da, 1); |
e4d82761 | 694 | |
6dbe713d SP |
695 | else |
696 | { | |
697 | if (k == 0x7ff00000 && u.i[LOW_HALF] == 0) | |
698 | __set_errno (EDOM); | |
699 | retval = x / x; /* |x| > 2^1024 */ | |
e4d82761 UD |
700 | } |
701 | ||
804360ed | 702 | return retval; |
e4d82761 UD |
703 | } |
704 | ||
705 | /************************************************************************/ | |
706 | /* Routine compute sin(x) for 2^-26 < |x|< 0.25 by Taylor with more */ | |
707 | /* precision and if still doesn't accurate enough by mpsin or dubsin */ | |
708 | /************************************************************************/ | |
709 | ||
31d3cc00 UD |
710 | static double |
711 | SECTION | |
6dbe713d SP |
712 | slow (double x) |
713 | { | |
4aafb73c SP |
714 | double res, cor, w[2]; |
715 | res = TAYLOR_SLOW (x, 0, cor); | |
6dbe713d SP |
716 | if (res == res + 1.0007 * cor) |
717 | return res; | |
718 | else | |
719 | { | |
720 | __dubsin (ABS (x), 0, w); | |
721 | if (w[0] == w[0] + 1.000000001 * w[1]) | |
722 | return (x > 0) ? w[0] : -w[0]; | |
723 | else | |
09544cbc | 724 | return (x > 0) ? __mpsin (x, 0, false) : -__mpsin (-x, 0, false); |
6dbe713d | 725 | } |
e4d82761 | 726 | } |
6dbe713d | 727 | |
e4d82761 | 728 | /*******************************************************************************/ |
c5d5d574 | 729 | /* Routine compute sin(x) for 0.25<|x|< 0.855469 by __sincostab.tbl and Taylor */ |
e4d82761 UD |
730 | /* and if result still doesn't accurate enough by mpsin or dubsin */ |
731 | /*******************************************************************************/ | |
732 | ||
31d3cc00 UD |
733 | static double |
734 | SECTION | |
6dbe713d SP |
735 | slow1 (double x) |
736 | { | |
e4d82761 | 737 | mynumber u; |
6dbe713d | 738 | double sn, ssn, cs, ccs, s, c, w[2], y, y1, y2, c1, c2, xx, cor, res; |
6dbe713d | 739 | y = ABS (x); |
196f7f5d SP |
740 | u.x = big + y; |
741 | y = y - (u.x - big); | |
6dbe713d SP |
742 | xx = y * y; |
743 | s = y * xx * (sn3 + xx * sn5); | |
744 | c = xx * (cs2 + xx * (cs4 + xx * cs6)); | |
b348e1e3 | 745 | SINCOS_TABLE_LOOKUP (u, sn, ssn, cs, ccs); |
6dbe713d | 746 | y1 = (y + t22) - t22; |
e4d82761 | 747 | y2 = y - y1; |
6dbe713d SP |
748 | c1 = (cs + t22) - t22; |
749 | c2 = (cs - c1) + ccs; | |
750 | cor = (ssn + s * ccs + cs * s + c2 * y + c1 * y2) - sn * c; | |
751 | y = sn + c1 * y1; | |
752 | cor = cor + ((sn - y) + c1 * y1); | |
753 | res = y + cor; | |
754 | cor = (y - res) + cor; | |
755 | if (res == res + 1.0005 * cor) | |
756 | return (x > 0) ? res : -res; | |
757 | else | |
758 | { | |
759 | __dubsin (ABS (x), 0, w); | |
760 | if (w[0] == w[0] + 1.000000005 * w[1]) | |
761 | return (x > 0) ? w[0] : -w[0]; | |
762 | else | |
09544cbc | 763 | return (x > 0) ? __mpsin (x, 0, false) : -__mpsin (-x, 0, false); |
6dbe713d | 764 | } |
e4d82761 | 765 | } |
6dbe713d | 766 | |
e4d82761 | 767 | /**************************************************************************/ |
af968f62 | 768 | /* Routine compute sin(x) for 0.855469 <|x|<2.426265 by __sincostab.tbl */ |
e4d82761 UD |
769 | /* and if result still doesn't accurate enough by mpsin or dubsin */ |
770 | /**************************************************************************/ | |
31d3cc00 UD |
771 | static double |
772 | SECTION | |
6dbe713d SP |
773 | slow2 (double x) |
774 | { | |
e4d82761 | 775 | mynumber u; |
6dbe713d | 776 | double sn, ssn, cs, ccs, s, c, w[2], y, y1, y2, e1, e2, xx, cor, res, del; |
7a74607f | 777 | |
6dbe713d | 778 | y = ABS (x); |
196f7f5d | 779 | y = hp0 - y; |
6dbe713d SP |
780 | if (y >= 0) |
781 | { | |
196f7f5d SP |
782 | u.x = big + y; |
783 | y = y - (u.x - big); | |
784 | del = hp1; | |
6dbe713d SP |
785 | } |
786 | else | |
787 | { | |
196f7f5d SP |
788 | u.x = big - y; |
789 | y = -(y + (u.x - big)); | |
790 | del = -hp1; | |
6dbe713d SP |
791 | } |
792 | xx = y * y; | |
793 | s = y * xx * (sn3 + xx * sn5); | |
794 | c = y * del + xx * (cs2 + xx * (cs4 + xx * cs6)); | |
b348e1e3 | 795 | SINCOS_TABLE_LOOKUP (u, sn, ssn, cs, ccs); |
6dbe713d SP |
796 | y1 = (y + t22) - t22; |
797 | y2 = (y - y1) + del; | |
798 | e1 = (sn + t22) - t22; | |
799 | e2 = (sn - e1) + ssn; | |
800 | cor = (ccs - cs * c - e1 * y2 - e2 * y) - sn * s; | |
801 | y = cs - e1 * y1; | |
802 | cor = cor + ((cs - y) - e1 * y1); | |
803 | res = y + cor; | |
804 | cor = (y - res) + cor; | |
805 | if (res == res + 1.0005 * cor) | |
806 | return (x > 0) ? res : -res; | |
807 | else | |
808 | { | |
196f7f5d SP |
809 | y = ABS (x) - hp0; |
810 | y1 = y - hp1; | |
811 | y2 = (y - y1) - hp1; | |
6dbe713d SP |
812 | __docos (y1, y2, w); |
813 | if (w[0] == w[0] + 1.000000005 * w[1]) | |
814 | return (x > 0) ? w[0] : -w[0]; | |
815 | else | |
09544cbc | 816 | return (x > 0) ? __mpsin (x, 0, false) : -__mpsin (-x, 0, false); |
6dbe713d | 817 | } |
e4d82761 | 818 | } |
6dbe713d | 819 | |
e4d82761 UD |
820 | /***************************************************************************/ |
821 | /* Routine compute sin(x+dx) (Double-Length number) where x is small enough*/ | |
822 | /* to use Taylor series around zero and (x+dx) */ | |
823 | /* in first or third quarter of unit circle.Routine receive also */ | |
824 | /* (right argument) the original value of x for computing error of */ | |
825 | /* result.And if result not accurate enough routine calls mpsin1 or dubsin */ | |
826 | /***************************************************************************/ | |
827 | ||
31d3cc00 UD |
828 | static double |
829 | SECTION | |
6dbe713d SP |
830 | sloww (double x, double dx, double orig) |
831 | { | |
4aafb73c | 832 | double y, t, res, cor, w[2], a, da, xn; |
6dbe713d SP |
833 | union |
834 | { | |
835 | int4 i[2]; | |
836 | double x; | |
837 | } v; | |
e4d82761 | 838 | int4 n; |
4aafb73c | 839 | res = TAYLOR_SLOW (x, dx, cor); |
6dbe713d SP |
840 | cor = |
841 | (cor > | |
842 | 0) ? 1.0005 * cor + ABS (orig) * 3.1e-30 : 1.0005 * cor - | |
843 | ABS (orig) * 3.1e-30; | |
844 | if (res == res + cor) | |
845 | return res; | |
846 | else | |
847 | { | |
848 | (x > 0) ? __dubsin (x, dx, w) : __dubsin (-x, -dx, w); | |
849 | if (w[1] > 0) | |
850 | cor = 1.000000001 * w[1] + ABS (orig) * 1.1e-30; | |
851 | else | |
852 | cor = 1.000000001 * w[1] - ABS (orig) * 1.1e-30; | |
853 | ||
854 | if (w[0] == w[0] + cor) | |
855 | return (x > 0) ? w[0] : -w[0]; | |
856 | else | |
857 | { | |
196f7f5d SP |
858 | t = (orig * hpinv + toint); |
859 | xn = t - toint; | |
6dbe713d | 860 | v.x = t; |
196f7f5d | 861 | y = (orig - xn * mp1) - xn * mp2; |
6dbe713d | 862 | n = v.i[LOW_HALF] & 3; |
196f7f5d | 863 | da = xn * pp3; |
6dbe713d SP |
864 | t = y - da; |
865 | da = (y - t) - da; | |
196f7f5d | 866 | y = xn * pp4; |
6dbe713d SP |
867 | a = t - y; |
868 | da = ((t - a) - y) + da; | |
869 | if (n & 2) | |
870 | { | |
871 | a = -a; | |
872 | da = -da; | |
873 | } | |
874 | (a > 0) ? __dubsin (a, da, w) : __dubsin (-a, -da, w); | |
875 | if (w[1] > 0) | |
876 | cor = 1.000000001 * w[1] + ABS (orig) * 1.1e-40; | |
877 | else | |
878 | cor = 1.000000001 * w[1] - ABS (orig) * 1.1e-40; | |
879 | ||
880 | if (w[0] == w[0] + cor) | |
881 | return (a > 0) ? w[0] : -w[0]; | |
882 | else | |
09544cbc | 883 | return __mpsin (orig, 0, true); |
6dbe713d | 884 | } |
e4d82761 | 885 | } |
e4d82761 | 886 | } |
6dbe713d | 887 | |
e4d82761 UD |
888 | /***************************************************************************/ |
889 | /* Routine compute sin(x+dx) (Double-Length number) where x in first or */ | |
890 | /* third quarter of unit circle.Routine receive also (right argument) the */ | |
891 | /* original value of x for computing error of result.And if result not */ | |
892 | /* accurate enough routine calls mpsin1 or dubsin */ | |
893 | /***************************************************************************/ | |
894 | ||
31d3cc00 UD |
895 | static double |
896 | SECTION | |
6dbe713d SP |
897 | sloww1 (double x, double dx, double orig) |
898 | { | |
e4d82761 | 899 | mynumber u; |
6dbe713d | 900 | double sn, ssn, cs, ccs, s, c, w[2], y, y1, y2, c1, c2, xx, cor, res; |
6dbe713d SP |
901 | |
902 | y = ABS (x); | |
196f7f5d SP |
903 | u.x = big + y; |
904 | y = y - (u.x - big); | |
6dbe713d SP |
905 | dx = (x > 0) ? dx : -dx; |
906 | xx = y * y; | |
907 | s = y * xx * (sn3 + xx * sn5); | |
908 | c = xx * (cs2 + xx * (cs4 + xx * cs6)); | |
b348e1e3 | 909 | SINCOS_TABLE_LOOKUP (u, sn, ssn, cs, ccs); |
6dbe713d SP |
910 | y1 = (y + t22) - t22; |
911 | y2 = (y - y1) + dx; | |
912 | c1 = (cs + t22) - t22; | |
913 | c2 = (cs - c1) + ccs; | |
914 | cor = (ssn + s * ccs + cs * s + c2 * y + c1 * y2 - sn * y * dx) - sn * c; | |
915 | y = sn + c1 * y1; | |
916 | cor = cor + ((sn - y) + c1 * y1); | |
917 | res = y + cor; | |
918 | cor = (y - res) + cor; | |
919 | ||
920 | if (cor > 0) | |
921 | cor = 1.0005 * cor + 3.1e-30 * ABS (orig); | |
922 | else | |
923 | cor = 1.0005 * cor - 3.1e-30 * ABS (orig); | |
924 | ||
925 | if (res == res + cor) | |
926 | return (x > 0) ? res : -res; | |
927 | else | |
928 | { | |
929 | __dubsin (ABS (x), dx, w); | |
930 | ||
931 | if (w[1] > 0) | |
932 | cor = 1.000000005 * w[1] + 1.1e-30 * ABS (orig); | |
933 | else | |
934 | cor = 1.000000005 * w[1] - 1.1e-30 * ABS (orig); | |
935 | ||
936 | if (w[0] == w[0] + cor) | |
937 | return (x > 0) ? w[0] : -w[0]; | |
938 | else | |
09544cbc | 939 | return __mpsin (orig, 0, true); |
6dbe713d | 940 | } |
e4d82761 | 941 | } |
6dbe713d | 942 | |
e4d82761 UD |
943 | /***************************************************************************/ |
944 | /* Routine compute sin(x+dx) (Double-Length number) where x in second or */ | |
945 | /* fourth quarter of unit circle.Routine receive also the original value */ | |
946 | /* and quarter(n= 1or 3)of x for computing error of result.And if result not*/ | |
947 | /* accurate enough routine calls mpsin1 or dubsin */ | |
948 | /***************************************************************************/ | |
949 | ||
31d3cc00 UD |
950 | static double |
951 | SECTION | |
6dbe713d SP |
952 | sloww2 (double x, double dx, double orig, int n) |
953 | { | |
e4d82761 | 954 | mynumber u; |
6dbe713d | 955 | double sn, ssn, cs, ccs, s, c, w[2], y, y1, y2, e1, e2, xx, cor, res; |
6dbe713d SP |
956 | |
957 | y = ABS (x); | |
196f7f5d SP |
958 | u.x = big + y; |
959 | y = y - (u.x - big); | |
6dbe713d SP |
960 | dx = (x > 0) ? dx : -dx; |
961 | xx = y * y; | |
962 | s = y * xx * (sn3 + xx * sn5); | |
963 | c = y * dx + xx * (cs2 + xx * (cs4 + xx * cs6)); | |
b348e1e3 | 964 | SINCOS_TABLE_LOOKUP (u, sn, ssn, cs, ccs); |
6dbe713d SP |
965 | |
966 | y1 = (y + t22) - t22; | |
967 | y2 = (y - y1) + dx; | |
968 | e1 = (sn + t22) - t22; | |
969 | e2 = (sn - e1) + ssn; | |
970 | cor = (ccs - cs * c - e1 * y2 - e2 * y) - sn * s; | |
971 | y = cs - e1 * y1; | |
972 | cor = cor + ((cs - y) - e1 * y1); | |
973 | res = y + cor; | |
974 | cor = (y - res) + cor; | |
975 | ||
976 | if (cor > 0) | |
977 | cor = 1.0005 * cor + 3.1e-30 * ABS (orig); | |
978 | else | |
979 | cor = 1.0005 * cor - 3.1e-30 * ABS (orig); | |
980 | ||
981 | if (res == res + cor) | |
982 | return (n & 2) ? -res : res; | |
983 | else | |
984 | { | |
985 | __docos (ABS (x), dx, w); | |
986 | ||
987 | if (w[1] > 0) | |
988 | cor = 1.000000005 * w[1] + 1.1e-30 * ABS (orig); | |
989 | else | |
990 | cor = 1.000000005 * w[1] - 1.1e-30 * ABS (orig); | |
991 | ||
992 | if (w[0] == w[0] + cor) | |
993 | return (n & 2) ? -w[0] : w[0]; | |
994 | else | |
09544cbc | 995 | return __mpsin (orig, 0, true); |
6dbe713d | 996 | } |
e4d82761 | 997 | } |
6dbe713d | 998 | |
e4d82761 UD |
999 | /***************************************************************************/ |
1000 | /* Routine compute sin(x+dx) or cos(x+dx) (Double-Length number) where x */ | |
1001 | /* is small enough to use Taylor series around zero and (x+dx) */ | |
1002 | /* in first or third quarter of unit circle.Routine receive also */ | |
1003 | /* (right argument) the original value of x for computing error of */ | |
1004 | /* result.And if result not accurate enough routine calls other routines */ | |
1005 | /***************************************************************************/ | |
1006 | ||
31d3cc00 UD |
1007 | static double |
1008 | SECTION | |
6dbe713d SP |
1009 | bsloww (double x, double dx, double orig, int n) |
1010 | { | |
4aafb73c SP |
1011 | double res, cor, w[2]; |
1012 | ||
1013 | res = TAYLOR_SLOW (x, dx, cor); | |
6dbe713d SP |
1014 | cor = (cor > 0) ? 1.0005 * cor + 1.1e-24 : 1.0005 * cor - 1.1e-24; |
1015 | if (res == res + cor) | |
1016 | return res; | |
1017 | else | |
1018 | { | |
1019 | (x > 0) ? __dubsin (x, dx, w) : __dubsin (-x, -dx, w); | |
1020 | if (w[1] > 0) | |
1021 | cor = 1.000000001 * w[1] + 1.1e-24; | |
1022 | else | |
1023 | cor = 1.000000001 * w[1] - 1.1e-24; | |
1024 | if (w[0] == w[0] + cor) | |
1025 | return (x > 0) ? w[0] : -w[0]; | |
1026 | else | |
09544cbc | 1027 | return (n & 1) ? __mpcos (orig, 0, true) : __mpsin (orig, 0, true); |
6dbe713d | 1028 | } |
e4d82761 UD |
1029 | } |
1030 | ||
1031 | /***************************************************************************/ | |
1032 | /* Routine compute sin(x+dx) or cos(x+dx) (Double-Length number) where x */ | |
1033 | /* in first or third quarter of unit circle.Routine receive also */ | |
1034 | /* (right argument) the original value of x for computing error of result.*/ | |
1035 | /* And if result not accurate enough routine calls other routines */ | |
1036 | /***************************************************************************/ | |
1037 | ||
31d3cc00 UD |
1038 | static double |
1039 | SECTION | |
6dbe713d SP |
1040 | bsloww1 (double x, double dx, double orig, int n) |
1041 | { | |
1042 | mynumber u; | |
1043 | double sn, ssn, cs, ccs, s, c, w[2], y, y1, y2, c1, c2, xx, cor, res; | |
6dbe713d SP |
1044 | |
1045 | y = ABS (x); | |
196f7f5d SP |
1046 | u.x = big + y; |
1047 | y = y - (u.x - big); | |
6dbe713d SP |
1048 | dx = (x > 0) ? dx : -dx; |
1049 | xx = y * y; | |
1050 | s = y * xx * (sn3 + xx * sn5); | |
1051 | c = xx * (cs2 + xx * (cs4 + xx * cs6)); | |
b348e1e3 | 1052 | SINCOS_TABLE_LOOKUP (u, sn, ssn, cs, ccs); |
6dbe713d SP |
1053 | y1 = (y + t22) - t22; |
1054 | y2 = (y - y1) + dx; | |
1055 | c1 = (cs + t22) - t22; | |
1056 | c2 = (cs - c1) + ccs; | |
1057 | cor = (ssn + s * ccs + cs * s + c2 * y + c1 * y2 - sn * y * dx) - sn * c; | |
1058 | y = sn + c1 * y1; | |
1059 | cor = cor + ((sn - y) + c1 * y1); | |
1060 | res = y + cor; | |
1061 | cor = (y - res) + cor; | |
1062 | cor = (cor > 0) ? 1.0005 * cor + 1.1e-24 : 1.0005 * cor - 1.1e-24; | |
1063 | if (res == res + cor) | |
1064 | return (x > 0) ? res : -res; | |
1065 | else | |
1066 | { | |
1067 | __dubsin (ABS (x), dx, w); | |
1068 | ||
1069 | if (w[1] > 0) | |
1070 | cor = 1.000000005 * w[1] + 1.1e-24; | |
1071 | else | |
1072 | cor = 1.000000005 * w[1] - 1.1e-24; | |
1073 | ||
1074 | if (w[0] == w[0] + cor) | |
1075 | return (x > 0) ? w[0] : -w[0]; | |
1076 | else | |
09544cbc | 1077 | return (n & 1) ? __mpcos (orig, 0, true) : __mpsin (orig, 0, true); |
6dbe713d | 1078 | } |
e4d82761 UD |
1079 | } |
1080 | ||
1081 | /***************************************************************************/ | |
1082 | /* Routine compute sin(x+dx) or cos(x+dx) (Double-Length number) where x */ | |
1083 | /* in second or fourth quarter of unit circle.Routine receive also the */ | |
1084 | /* original value and quarter(n= 1or 3)of x for computing error of result. */ | |
1085 | /* And if result not accurate enough routine calls other routines */ | |
1086 | /***************************************************************************/ | |
1087 | ||
31d3cc00 UD |
1088 | static double |
1089 | SECTION | |
6dbe713d SP |
1090 | bsloww2 (double x, double dx, double orig, int n) |
1091 | { | |
1092 | mynumber u; | |
1093 | double sn, ssn, cs, ccs, s, c, w[2], y, y1, y2, e1, e2, xx, cor, res; | |
6dbe713d SP |
1094 | |
1095 | y = ABS (x); | |
196f7f5d SP |
1096 | u.x = big + y; |
1097 | y = y - (u.x - big); | |
6dbe713d SP |
1098 | dx = (x > 0) ? dx : -dx; |
1099 | xx = y * y; | |
1100 | s = y * xx * (sn3 + xx * sn5); | |
1101 | c = y * dx + xx * (cs2 + xx * (cs4 + xx * cs6)); | |
b348e1e3 | 1102 | SINCOS_TABLE_LOOKUP (u, sn, ssn, cs, ccs); |
6dbe713d SP |
1103 | |
1104 | y1 = (y + t22) - t22; | |
1105 | y2 = (y - y1) + dx; | |
1106 | e1 = (sn + t22) - t22; | |
1107 | e2 = (sn - e1) + ssn; | |
1108 | cor = (ccs - cs * c - e1 * y2 - e2 * y) - sn * s; | |
1109 | y = cs - e1 * y1; | |
1110 | cor = cor + ((cs - y) - e1 * y1); | |
1111 | res = y + cor; | |
1112 | cor = (y - res) + cor; | |
1113 | cor = (cor > 0) ? 1.0005 * cor + 1.1e-24 : 1.0005 * cor - 1.1e-24; | |
1114 | if (res == res + cor) | |
1115 | return (n & 2) ? -res : res; | |
1116 | else | |
1117 | { | |
1118 | __docos (ABS (x), dx, w); | |
1119 | ||
1120 | if (w[1] > 0) | |
1121 | cor = 1.000000005 * w[1] + 1.1e-24; | |
1122 | else | |
1123 | cor = 1.000000005 * w[1] - 1.1e-24; | |
1124 | ||
1125 | if (w[0] == w[0] + cor) | |
1126 | return (n & 2) ? -w[0] : w[0]; | |
1127 | else | |
09544cbc | 1128 | return (n & 1) ? __mpsin (orig, 0, true) : __mpcos (orig, 0, true); |
6dbe713d | 1129 | } |
e4d82761 UD |
1130 | } |
1131 | ||
1132 | /************************************************************************/ | |
1133 | /* Routine compute cos(x) for 2^-27 < |x|< 0.25 by Taylor with more */ | |
1134 | /* precision and if still doesn't accurate enough by mpcos or docos */ | |
1135 | /************************************************************************/ | |
1136 | ||
31d3cc00 UD |
1137 | static double |
1138 | SECTION | |
6dbe713d SP |
1139 | cslow2 (double x) |
1140 | { | |
e4d82761 | 1141 | mynumber u; |
6dbe713d | 1142 | double sn, ssn, cs, ccs, s, c, w[2], y, y1, y2, e1, e2, xx, cor, res; |
6dbe713d SP |
1143 | |
1144 | y = ABS (x); | |
196f7f5d SP |
1145 | u.x = big + y; |
1146 | y = y - (u.x - big); | |
6dbe713d SP |
1147 | xx = y * y; |
1148 | s = y * xx * (sn3 + xx * sn5); | |
1149 | c = xx * (cs2 + xx * (cs4 + xx * cs6)); | |
b348e1e3 | 1150 | SINCOS_TABLE_LOOKUP (u, sn, ssn, cs, ccs); |
6dbe713d | 1151 | y1 = (y + t22) - t22; |
e4d82761 | 1152 | y2 = y - y1; |
6dbe713d SP |
1153 | e1 = (sn + t22) - t22; |
1154 | e2 = (sn - e1) + ssn; | |
1155 | cor = (ccs - cs * c - e1 * y2 - e2 * y) - sn * s; | |
1156 | y = cs - e1 * y1; | |
1157 | cor = cor + ((cs - y) - e1 * y1); | |
1158 | res = y + cor; | |
1159 | cor = (y - res) + cor; | |
1160 | if (res == res + 1.0005 * cor) | |
e4d82761 | 1161 | return res; |
6dbe713d SP |
1162 | else |
1163 | { | |
1164 | y = ABS (x); | |
1165 | __docos (y, 0, w); | |
1166 | if (w[0] == w[0] + 1.000000005 * w[1]) | |
1167 | return w[0]; | |
1168 | else | |
09544cbc | 1169 | return __mpcos (x, 0, false); |
6dbe713d | 1170 | } |
e4d82761 UD |
1171 | } |
1172 | ||
1173 | /***************************************************************************/ | |
1174 | /* Routine compute cos(x+dx) (Double-Length number) where x is small enough*/ | |
1175 | /* to use Taylor series around zero and (x+dx) .Routine receive also */ | |
1176 | /* (right argument) the original value of x for computing error of */ | |
1177 | /* result.And if result not accurate enough routine calls other routines */ | |
1178 | /***************************************************************************/ | |
1179 | ||
1180 | ||
31d3cc00 UD |
1181 | static double |
1182 | SECTION | |
6dbe713d SP |
1183 | csloww (double x, double dx, double orig) |
1184 | { | |
4aafb73c | 1185 | double y, t, res, cor, w[2], a, da, xn; |
6dbe713d SP |
1186 | union |
1187 | { | |
1188 | int4 i[2]; | |
1189 | double x; | |
1190 | } v; | |
e4d82761 | 1191 | int4 n; |
6dbe713d | 1192 | |
6dbe713d | 1193 | /* Taylor series */ |
4aafb73c | 1194 | t = TAYLOR_SLOW (x, dx, cor); |
6dbe713d SP |
1195 | |
1196 | if (cor > 0) | |
1197 | cor = 1.0005 * cor + ABS (orig) * 3.1e-30; | |
1198 | else | |
1199 | cor = 1.0005 * cor - ABS (orig) * 3.1e-30; | |
1200 | ||
1201 | if (res == res + cor) | |
1202 | return res; | |
1203 | else | |
1204 | { | |
1205 | (x > 0) ? __dubsin (x, dx, w) : __dubsin (-x, -dx, w); | |
1206 | ||
1207 | if (w[1] > 0) | |
1208 | cor = 1.000000001 * w[1] + ABS (orig) * 1.1e-30; | |
1209 | else | |
1210 | cor = 1.000000001 * w[1] - ABS (orig) * 1.1e-30; | |
1211 | ||
1212 | if (w[0] == w[0] + cor) | |
1213 | return (x > 0) ? w[0] : -w[0]; | |
1214 | else | |
1215 | { | |
196f7f5d SP |
1216 | t = (orig * hpinv + toint); |
1217 | xn = t - toint; | |
6dbe713d | 1218 | v.x = t; |
196f7f5d | 1219 | y = (orig - xn * mp1) - xn * mp2; |
6dbe713d | 1220 | n = v.i[LOW_HALF] & 3; |
196f7f5d | 1221 | da = xn * pp3; |
6dbe713d SP |
1222 | t = y - da; |
1223 | da = (y - t) - da; | |
196f7f5d | 1224 | y = xn * pp4; |
6dbe713d SP |
1225 | a = t - y; |
1226 | da = ((t - a) - y) + da; | |
1227 | if (n == 1) | |
1228 | { | |
1229 | a = -a; | |
1230 | da = -da; | |
1231 | } | |
1232 | (a > 0) ? __dubsin (a, da, w) : __dubsin (-a, -da, w); | |
1233 | ||
1234 | if (w[1] > 0) | |
1235 | cor = 1.000000001 * w[1] + ABS (orig) * 1.1e-40; | |
1236 | else | |
1237 | cor = 1.000000001 * w[1] - ABS (orig) * 1.1e-40; | |
1238 | ||
1239 | if (w[0] == w[0] + cor) | |
1240 | return (a > 0) ? w[0] : -w[0]; | |
1241 | else | |
09544cbc | 1242 | return __mpcos (orig, 0, true); |
6dbe713d | 1243 | } |
e4d82761 | 1244 | } |
e4d82761 UD |
1245 | } |
1246 | ||
1247 | /***************************************************************************/ | |
1248 | /* Routine compute sin(x+dx) (Double-Length number) where x in first or */ | |
1249 | /* third quarter of unit circle.Routine receive also (right argument) the */ | |
1250 | /* original value of x for computing error of result.And if result not */ | |
1251 | /* accurate enough routine calls other routines */ | |
1252 | /***************************************************************************/ | |
1253 | ||
31d3cc00 UD |
1254 | static double |
1255 | SECTION | |
6dbe713d SP |
1256 | csloww1 (double x, double dx, double orig) |
1257 | { | |
e4d82761 | 1258 | mynumber u; |
6dbe713d | 1259 | double sn, ssn, cs, ccs, s, c, w[2], y, y1, y2, c1, c2, xx, cor, res; |
6dbe713d SP |
1260 | |
1261 | y = ABS (x); | |
196f7f5d SP |
1262 | u.x = big + y; |
1263 | y = y - (u.x - big); | |
6dbe713d SP |
1264 | dx = (x > 0) ? dx : -dx; |
1265 | xx = y * y; | |
1266 | s = y * xx * (sn3 + xx * sn5); | |
1267 | c = xx * (cs2 + xx * (cs4 + xx * cs6)); | |
b348e1e3 | 1268 | SINCOS_TABLE_LOOKUP (u, sn, ssn, cs, ccs); |
6dbe713d SP |
1269 | y1 = (y + t22) - t22; |
1270 | y2 = (y - y1) + dx; | |
1271 | c1 = (cs + t22) - t22; | |
1272 | c2 = (cs - c1) + ccs; | |
1273 | cor = (ssn + s * ccs + cs * s + c2 * y + c1 * y2 - sn * y * dx) - sn * c; | |
1274 | y = sn + c1 * y1; | |
1275 | cor = cor + ((sn - y) + c1 * y1); | |
1276 | res = y + cor; | |
1277 | cor = (y - res) + cor; | |
1278 | ||
1279 | if (cor > 0) | |
1280 | cor = 1.0005 * cor + 3.1e-30 * ABS (orig); | |
1281 | else | |
1282 | cor = 1.0005 * cor - 3.1e-30 * ABS (orig); | |
1283 | ||
1284 | if (res == res + cor) | |
1285 | return (x > 0) ? res : -res; | |
1286 | else | |
1287 | { | |
1288 | __dubsin (ABS (x), dx, w); | |
1289 | if (w[1] > 0) | |
1290 | cor = 1.000000005 * w[1] + 1.1e-30 * ABS (orig); | |
1291 | else | |
1292 | cor = 1.000000005 * w[1] - 1.1e-30 * ABS (orig); | |
1293 | if (w[0] == w[0] + cor) | |
1294 | return (x > 0) ? w[0] : -w[0]; | |
1295 | else | |
09544cbc | 1296 | return __mpcos (orig, 0, true); |
6dbe713d | 1297 | } |
e4d82761 UD |
1298 | } |
1299 | ||
1300 | ||
1301 | /***************************************************************************/ | |
1302 | /* Routine compute sin(x+dx) (Double-Length number) where x in second or */ | |
1303 | /* fourth quarter of unit circle.Routine receive also the original value */ | |
1304 | /* and quarter(n= 1or 3)of x for computing error of result.And if result not*/ | |
1305 | /* accurate enough routine calls other routines */ | |
1306 | /***************************************************************************/ | |
1307 | ||
31d3cc00 UD |
1308 | static double |
1309 | SECTION | |
6dbe713d SP |
1310 | csloww2 (double x, double dx, double orig, int n) |
1311 | { | |
e4d82761 | 1312 | mynumber u; |
6dbe713d | 1313 | double sn, ssn, cs, ccs, s, c, w[2], y, y1, y2, e1, e2, xx, cor, res; |
6dbe713d SP |
1314 | |
1315 | y = ABS (x); | |
196f7f5d SP |
1316 | u.x = big + y; |
1317 | y = y - (u.x - big); | |
6dbe713d SP |
1318 | dx = (x > 0) ? dx : -dx; |
1319 | xx = y * y; | |
1320 | s = y * xx * (sn3 + xx * sn5); | |
1321 | c = y * dx + xx * (cs2 + xx * (cs4 + xx * cs6)); | |
b348e1e3 | 1322 | SINCOS_TABLE_LOOKUP (u, sn, ssn, cs, ccs); |
6dbe713d SP |
1323 | |
1324 | y1 = (y + t22) - t22; | |
1325 | y2 = (y - y1) + dx; | |
1326 | e1 = (sn + t22) - t22; | |
1327 | e2 = (sn - e1) + ssn; | |
1328 | cor = (ccs - cs * c - e1 * y2 - e2 * y) - sn * s; | |
1329 | y = cs - e1 * y1; | |
1330 | cor = cor + ((cs - y) - e1 * y1); | |
1331 | res = y + cor; | |
1332 | cor = (y - res) + cor; | |
1333 | ||
1334 | if (cor > 0) | |
1335 | cor = 1.0005 * cor + 3.1e-30 * ABS (orig); | |
1336 | else | |
1337 | cor = 1.0005 * cor - 3.1e-30 * ABS (orig); | |
1338 | ||
1339 | if (res == res + cor) | |
1340 | return (n) ? -res : res; | |
1341 | else | |
1342 | { | |
1343 | __docos (ABS (x), dx, w); | |
1344 | if (w[1] > 0) | |
1345 | cor = 1.000000005 * w[1] + 1.1e-30 * ABS (orig); | |
1346 | else | |
1347 | cor = 1.000000005 * w[1] - 1.1e-30 * ABS (orig); | |
1348 | if (w[0] == w[0] + cor) | |
1349 | return (n) ? -w[0] : w[0]; | |
1350 | else | |
09544cbc | 1351 | return __mpcos (orig, 0, true); |
6dbe713d | 1352 | } |
e4d82761 UD |
1353 | } |
1354 | ||
af968f62 | 1355 | #ifndef __cos |
ca58f1db | 1356 | weak_alias (__cos, cos) |
af968f62 UD |
1357 | # ifdef NO_LONG_DOUBLE |
1358 | strong_alias (__cos, __cosl) | |
1359 | weak_alias (__cos, cosl) | |
1360 | # endif | |
1361 | #endif | |
1362 | #ifndef __sin | |
ca58f1db | 1363 | weak_alias (__sin, sin) |
af968f62 | 1364 | # ifdef NO_LONG_DOUBLE |
ca58f1db UD |
1365 | strong_alias (__sin, __sinl) |
1366 | weak_alias (__sin, sinl) | |
af968f62 | 1367 | # endif |
cccda09f | 1368 | #endif |