| 1 | /* |
| 2 | * IBM Accurate Mathematical Library |
| 3 | * written by International Business Machines Corp. |
| 4 | * Copyright (C) 2001-2016 Free Software Foundation, Inc. |
| 5 | * |
| 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. |
| 10 | * |
| 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. |
| 15 | * |
| 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/>. |
| 18 | */ |
| 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 | /* FILES NEEDED: dla.h endian.h mpa.h mydefs.h usncs.h */ |
| 36 | /* branred.c sincos32.c dosincos.c mpa.c */ |
| 37 | /* sincos.tbl */ |
| 38 | /* */ |
| 39 | /* An ultimate sin and routine. Given an IEEE double machine number x */ |
| 40 | /* it computes the correctly rounded (to nearest) value of sin(x) or cos(x) */ |
| 41 | /* Assumption: Machine arithmetic operations are performed in */ |
| 42 | /* round to nearest mode of IEEE 754 standard. */ |
| 43 | /* */ |
| 44 | /****************************************************************************/ |
| 45 | |
| 46 | |
| 47 | #include <errno.h> |
| 48 | #include <float.h> |
| 49 | #include "endian.h" |
| 50 | #include "mydefs.h" |
| 51 | #include "usncs.h" |
| 52 | #include "MathLib.h" |
| 53 | #include <math.h> |
| 54 | #include <math_private.h> |
| 55 | #include <fenv.h> |
| 56 | |
| 57 | /* Helper macros to compute sin of the input values. */ |
| 58 | #define POLYNOMIAL2(xx) ((((s5 * (xx) + s4) * (xx) + s3) * (xx) + s2) * (xx)) |
| 59 | |
| 60 | #define POLYNOMIAL(xx) (POLYNOMIAL2 (xx) + s1) |
| 61 | |
| 62 | /* The computed polynomial is a variation of the Taylor series expansion for |
| 63 | sin(a): |
| 64 | |
| 65 | a - a^3/3! + a^5/5! - a^7/7! + a^9/9! + (1 - a^2) * da / 2 |
| 66 | |
| 67 | The constants s1, s2, s3, etc. are pre-computed values of 1/3!, 1/5! and so |
| 68 | on. The result is returned to LHS and correction in COR. */ |
| 69 | #define TAYLOR_SIN(xx, a, da, cor) \ |
| 70 | ({ \ |
| 71 | double t = ((POLYNOMIAL (xx) * (a) - 0.5 * (da)) * (xx) + (da)); \ |
| 72 | double res = (a) + t; \ |
| 73 | (cor) = ((a) - res) + t; \ |
| 74 | res; \ |
| 75 | }) |
| 76 | |
| 77 | /* This is again a variation of the Taylor series expansion with the term |
| 78 | x^3/3! expanded into the following for better accuracy: |
| 79 | |
| 80 | bb * x ^ 3 + 3 * aa * x * x1 * x2 + aa * x1 ^ 3 + aa * x2 ^ 3 |
| 81 | |
| 82 | The correction term is dx and bb + aa = -1/3! |
| 83 | */ |
| 84 | #define TAYLOR_SLOW(x0, dx, cor) \ |
| 85 | ({ \ |
| 86 | static const double th2_36 = 206158430208.0; /* 1.5*2**37 */ \ |
| 87 | double xx = (x0) * (x0); \ |
| 88 | double x1 = ((x0) + th2_36) - th2_36; \ |
| 89 | double y = aa * x1 * x1 * x1; \ |
| 90 | double r = (x0) + y; \ |
| 91 | double x2 = ((x0) - x1) + (dx); \ |
| 92 | double t = (((POLYNOMIAL2 (xx) + bb) * xx + 3.0 * aa * x1 * x2) \ |
| 93 | * (x0) + aa * x2 * x2 * x2 + (dx)); \ |
| 94 | t = (((x0) - r) + y) + t; \ |
| 95 | double res = r + t; \ |
| 96 | (cor) = (r - res) + t; \ |
| 97 | res; \ |
| 98 | }) |
| 99 | |
| 100 | #define SINCOS_TABLE_LOOKUP(u, sn, ssn, cs, ccs) \ |
| 101 | ({ \ |
| 102 | int4 k = u.i[LOW_HALF] << 2; \ |
| 103 | sn = __sincostab.x[k]; \ |
| 104 | ssn = __sincostab.x[k + 1]; \ |
| 105 | cs = __sincostab.x[k + 2]; \ |
| 106 | ccs = __sincostab.x[k + 3]; \ |
| 107 | }) |
| 108 | |
| 109 | #ifndef SECTION |
| 110 | # define SECTION |
| 111 | #endif |
| 112 | |
| 113 | extern const union |
| 114 | { |
| 115 | int4 i[880]; |
| 116 | double x[440]; |
| 117 | } __sincostab attribute_hidden; |
| 118 | |
| 119 | static const double |
| 120 | sn3 = -1.66666666666664880952546298448555E-01, |
| 121 | sn5 = 8.33333214285722277379541354343671E-03, |
| 122 | cs2 = 4.99999999999999999999950396842453E-01, |
| 123 | cs4 = -4.16666666666664434524222570944589E-02, |
| 124 | cs6 = 1.38888874007937613028114285595617E-03; |
| 125 | |
| 126 | static const double t22 = 0x1.8p22; |
| 127 | |
| 128 | void __dubsin (double x, double dx, double w[]); |
| 129 | void __docos (double x, double dx, double w[]); |
| 130 | double __mpsin (double x, double dx, bool reduce_range); |
| 131 | double __mpcos (double x, double dx, bool reduce_range); |
| 132 | static double slow (double x); |
| 133 | static double slow1 (double x); |
| 134 | static double slow2 (double x); |
| 135 | static double sloww (double x, double dx, double orig, int n); |
| 136 | static double sloww1 (double x, double dx, double orig, int m, int n); |
| 137 | static double sloww2 (double x, double dx, double orig, int n); |
| 138 | static double bsloww (double x, double dx, double orig, int n); |
| 139 | static double bsloww1 (double x, double dx, double orig, int n); |
| 140 | static double bsloww2 (double x, double dx, double orig, int n); |
| 141 | int __branred (double x, double *a, double *aa); |
| 142 | static double cslow2 (double x); |
| 143 | |
| 144 | /* Given a number partitioned into U and X such that U is an index into the |
| 145 | sin/cos table, this macro computes the cosine of the number by combining |
| 146 | the sin and cos of X (as computed by a variation of the Taylor series) with |
| 147 | the values looked up from the sin/cos table to get the result in RES and a |
| 148 | correction value in COR. */ |
| 149 | static double |
| 150 | do_cos (mynumber u, double x, double *corp) |
| 151 | { |
| 152 | double xx, s, sn, ssn, c, cs, ccs, res, cor; |
| 153 | xx = x * x; |
| 154 | s = x + x * xx * (sn3 + xx * sn5); |
| 155 | c = xx * (cs2 + xx * (cs4 + xx * cs6)); |
| 156 | SINCOS_TABLE_LOOKUP (u, sn, ssn, cs, ccs); |
| 157 | cor = (ccs - s * ssn - cs * c) - sn * s; |
| 158 | res = cs + cor; |
| 159 | cor = (cs - res) + cor; |
| 160 | *corp = cor; |
| 161 | return res; |
| 162 | } |
| 163 | |
| 164 | /* A more precise variant of DO_COS where the number is partitioned into U, X |
| 165 | and DX. EPS is the adjustment to the correction COR. */ |
| 166 | static double |
| 167 | do_cos_slow (mynumber u, double x, double dx, double eps, double *corp) |
| 168 | { |
| 169 | double xx, y, x1, x2, e1, e2, res, cor; |
| 170 | double s, sn, ssn, c, cs, ccs; |
| 171 | xx = x * x; |
| 172 | s = x * xx * (sn3 + xx * sn5); |
| 173 | c = x * dx + xx * (cs2 + xx * (cs4 + xx * cs6)); |
| 174 | SINCOS_TABLE_LOOKUP (u, sn, ssn, cs, ccs); |
| 175 | x1 = (x + t22) - t22; |
| 176 | x2 = (x - x1) + dx; |
| 177 | e1 = (sn + t22) - t22; |
| 178 | e2 = (sn - e1) + ssn; |
| 179 | cor = (ccs - cs * c - e1 * x2 - e2 * x) - sn * s; |
| 180 | y = cs - e1 * x1; |
| 181 | cor = cor + ((cs - y) - e1 * x1); |
| 182 | res = y + cor; |
| 183 | cor = (y - res) + cor; |
| 184 | if (cor > 0) |
| 185 | cor = 1.0005 * cor + eps; |
| 186 | else |
| 187 | cor = 1.0005 * cor - eps; |
| 188 | *corp = cor; |
| 189 | return res; |
| 190 | } |
| 191 | |
| 192 | /* Given a number partitioned into U and X and DX such that U is an index into |
| 193 | the sin/cos table, this macro computes the sine of the number by combining |
| 194 | the sin and cos of X (as computed by a variation of the Taylor series) with |
| 195 | the values looked up from the sin/cos table to get the result in RES and a |
| 196 | correction value in COR. */ |
| 197 | static double |
| 198 | do_sin (mynumber u, double x, double dx, double *corp) |
| 199 | { |
| 200 | double xx, s, sn, ssn, c, cs, ccs, cor, res; |
| 201 | xx = x * x; |
| 202 | s = x + (dx + x * xx * (sn3 + xx * sn5)); |
| 203 | c = x * dx + xx * (cs2 + xx * (cs4 + xx * cs6)); |
| 204 | SINCOS_TABLE_LOOKUP (u, sn, ssn, cs, ccs); |
| 205 | cor = (ssn + s * ccs - sn * c) + cs * s; |
| 206 | res = sn + cor; |
| 207 | cor = (sn - res) + cor; |
| 208 | *corp = cor; |
| 209 | return res; |
| 210 | } |
| 211 | |
| 212 | /* A more precise variant of res = do_sin where the number is partitioned into U, X |
| 213 | and DX. EPS is the adjustment to the correction COR. */ |
| 214 | static double |
| 215 | do_sin_slow (mynumber u, double x, double dx, double eps, double *corp) |
| 216 | { |
| 217 | double xx, y, x1, x2, c1, c2, res, cor; |
| 218 | double s, sn, ssn, c, cs, ccs; |
| 219 | xx = x * x; |
| 220 | s = x * xx * (sn3 + xx * sn5); |
| 221 | c = xx * (cs2 + xx * (cs4 + xx * cs6)); |
| 222 | SINCOS_TABLE_LOOKUP (u, sn, ssn, cs, ccs); |
| 223 | x1 = (x + t22) - t22; |
| 224 | x2 = (x - x1) + dx; |
| 225 | c1 = (cs + t22) - t22; |
| 226 | c2 = (cs - c1) + ccs; |
| 227 | cor = (ssn + s * ccs + cs * s + c2 * x + c1 * x2 - sn * x * dx) - sn * c; |
| 228 | y = sn + c1 * x1; |
| 229 | cor = cor + ((sn - y) + c1 * x1); |
| 230 | res = y + cor; |
| 231 | cor = (y - res) + cor; |
| 232 | if (cor > 0) |
| 233 | cor = 1.0005 * cor + eps; |
| 234 | else |
| 235 | cor = 1.0005 * cor - eps; |
| 236 | *corp = cor; |
| 237 | return res; |
| 238 | } |
| 239 | |
| 240 | /* Reduce range of X and compute sin of a + da. K is the amount by which to |
| 241 | rotate the quadrants. This allows us to use the same routine to compute cos |
| 242 | by simply rotating the quadrants by 1. */ |
| 243 | static inline double |
| 244 | __always_inline |
| 245 | reduce_and_compute (double x, unsigned int k) |
| 246 | { |
| 247 | double retval = 0, a, da; |
| 248 | unsigned int n = __branred (x, &a, &da); |
| 249 | k = (n + k) % 4; |
| 250 | switch (k) |
| 251 | { |
| 252 | case 0: |
| 253 | if (a * a < 0.01588) |
| 254 | retval = bsloww (a, da, x, n); |
| 255 | else |
| 256 | retval = bsloww1 (a, da, x, n); |
| 257 | break; |
| 258 | case 2: |
| 259 | if (a * a < 0.01588) |
| 260 | retval = bsloww (-a, -da, x, n); |
| 261 | else |
| 262 | retval = bsloww1 (-a, -da, x, n); |
| 263 | break; |
| 264 | |
| 265 | case 1: |
| 266 | case 3: |
| 267 | retval = bsloww2 (a, da, x, n); |
| 268 | break; |
| 269 | } |
| 270 | return retval; |
| 271 | } |
| 272 | |
| 273 | static inline int4 |
| 274 | __always_inline |
| 275 | reduce_sincos_1 (double x, double *a, double *da) |
| 276 | { |
| 277 | mynumber v; |
| 278 | |
| 279 | double t = (x * hpinv + toint); |
| 280 | double xn = t - toint; |
| 281 | v.x = t; |
| 282 | double y = (x - xn * mp1) - xn * mp2; |
| 283 | int4 n = v.i[LOW_HALF] & 3; |
| 284 | double db = xn * mp3; |
| 285 | double b = y - db; |
| 286 | db = (y - b) - db; |
| 287 | |
| 288 | *a = b; |
| 289 | *da = db; |
| 290 | |
| 291 | return n; |
| 292 | } |
| 293 | |
| 294 | /* Compute sin (A + DA). cos can be computed by shifting the quadrant N |
| 295 | clockwise. */ |
| 296 | static double |
| 297 | __always_inline |
| 298 | do_sincos_1 (double a, double da, double x, int4 n, int4 k) |
| 299 | { |
| 300 | double xx, retval, res, cor, y; |
| 301 | mynumber u; |
| 302 | int m; |
| 303 | double eps = fabs (x) * 1.2e-30; |
| 304 | |
| 305 | int k1 = (n + k) & 3; |
| 306 | switch (k1) |
| 307 | { /* quarter of unit circle */ |
| 308 | case 2: |
| 309 | a = -a; |
| 310 | da = -da; |
| 311 | case 0: |
| 312 | xx = a * a; |
| 313 | if (xx < 0.01588) |
| 314 | { |
| 315 | /* Taylor series. */ |
| 316 | res = TAYLOR_SIN (xx, a, da, cor); |
| 317 | cor = (cor > 0) ? 1.02 * cor + eps : 1.02 * cor - eps; |
| 318 | retval = (res == res + cor) ? res : sloww (a, da, x, k); |
| 319 | } |
| 320 | else |
| 321 | { |
| 322 | if (a > 0) |
| 323 | m = 1; |
| 324 | else |
| 325 | { |
| 326 | m = 0; |
| 327 | a = -a; |
| 328 | da = -da; |
| 329 | } |
| 330 | u.x = big + a; |
| 331 | y = a - (u.x - big); |
| 332 | res = do_sin (u, y, da, &cor); |
| 333 | cor = (cor > 0) ? 1.035 * cor + eps : 1.035 * cor - eps; |
| 334 | retval = ((res == res + cor) ? ((m) ? res : -res) |
| 335 | : sloww1 (a, da, x, m, k)); |
| 336 | } |
| 337 | break; |
| 338 | |
| 339 | case 1: |
| 340 | case 3: |
| 341 | if (a < 0) |
| 342 | { |
| 343 | a = -a; |
| 344 | da = -da; |
| 345 | } |
| 346 | u.x = big + a; |
| 347 | y = a - (u.x - big) + da; |
| 348 | res = do_cos (u, y, &cor); |
| 349 | cor = (cor > 0) ? 1.025 * cor + eps : 1.025 * cor - eps; |
| 350 | retval = ((res == res + cor) ? ((k1 & 2) ? -res : res) |
| 351 | : sloww2 (a, da, x, n)); |
| 352 | break; |
| 353 | } |
| 354 | |
| 355 | return retval; |
| 356 | } |
| 357 | |
| 358 | static inline int4 |
| 359 | __always_inline |
| 360 | reduce_sincos_2 (double x, double *a, double *da) |
| 361 | { |
| 362 | mynumber v; |
| 363 | |
| 364 | double t = (x * hpinv + toint); |
| 365 | double xn = t - toint; |
| 366 | v.x = t; |
| 367 | double xn1 = (xn + 8.0e22) - 8.0e22; |
| 368 | double xn2 = xn - xn1; |
| 369 | double y = ((((x - xn1 * mp1) - xn1 * mp2) - xn2 * mp1) - xn2 * mp2); |
| 370 | int4 n = v.i[LOW_HALF] & 3; |
| 371 | double db = xn1 * pp3; |
| 372 | t = y - db; |
| 373 | db = (y - t) - db; |
| 374 | db = (db - xn2 * pp3) - xn * pp4; |
| 375 | double b = t + db; |
| 376 | db = (t - b) + db; |
| 377 | |
| 378 | *a = b; |
| 379 | *da = db; |
| 380 | |
| 381 | return n; |
| 382 | } |
| 383 | |
| 384 | /* Compute sin (A + DA). cos can be computed by shifting the quadrant N |
| 385 | clockwise. */ |
| 386 | static double |
| 387 | __always_inline |
| 388 | do_sincos_2 (double a, double da, double x, int4 n, int4 k) |
| 389 | { |
| 390 | double res, retval, cor, xx; |
| 391 | mynumber u; |
| 392 | |
| 393 | double eps = 1.0e-24; |
| 394 | |
| 395 | k = (n + k) & 3; |
| 396 | |
| 397 | switch (k) |
| 398 | { |
| 399 | case 2: |
| 400 | a = -a; |
| 401 | da = -da; |
| 402 | /* Fall through. */ |
| 403 | case 0: |
| 404 | xx = a * a; |
| 405 | if (xx < 0.01588) |
| 406 | { |
| 407 | /* Taylor series. */ |
| 408 | res = TAYLOR_SIN (xx, a, da, cor); |
| 409 | cor = (cor > 0) ? 1.02 * cor + eps : 1.02 * cor - eps; |
| 410 | retval = (res == res + cor) ? res : bsloww (a, da, x, n); |
| 411 | } |
| 412 | else |
| 413 | { |
| 414 | double t, db, y; |
| 415 | int m; |
| 416 | if (a > 0) |
| 417 | { |
| 418 | m = 1; |
| 419 | t = a; |
| 420 | db = da; |
| 421 | } |
| 422 | else |
| 423 | { |
| 424 | m = 0; |
| 425 | t = -a; |
| 426 | db = -da; |
| 427 | } |
| 428 | u.x = big + t; |
| 429 | y = t - (u.x - big); |
| 430 | res = do_sin (u, y, db, &cor); |
| 431 | cor = (cor > 0) ? 1.035 * cor + eps : 1.035 * cor - eps; |
| 432 | retval = ((res == res + cor) ? ((m) ? res : -res) |
| 433 | : bsloww1 (a, da, x, n)); |
| 434 | } |
| 435 | break; |
| 436 | |
| 437 | case 1: |
| 438 | case 3: |
| 439 | if (a < 0) |
| 440 | { |
| 441 | a = -a; |
| 442 | da = -da; |
| 443 | } |
| 444 | u.x = big + a; |
| 445 | double y = a - (u.x - big) + da; |
| 446 | res = do_cos (u, y, &cor); |
| 447 | cor = (cor > 0) ? 1.025 * cor + eps : 1.025 * cor - eps; |
| 448 | retval = ((res == res + cor) ? ((n & 2) ? -res : res) |
| 449 | : bsloww2 (a, da, x, n)); |
| 450 | break; |
| 451 | } |
| 452 | |
| 453 | return retval; |
| 454 | } |
| 455 | |
| 456 | /*******************************************************************/ |
| 457 | /* An ultimate sin routine. Given an IEEE double machine number x */ |
| 458 | /* it computes the correctly rounded (to nearest) value of sin(x) */ |
| 459 | /*******************************************************************/ |
| 460 | #ifdef IN_SINCOS |
| 461 | static double |
| 462 | #else |
| 463 | double |
| 464 | SECTION |
| 465 | #endif |
| 466 | __sin (double x) |
| 467 | { |
| 468 | double xx, res, t, cor, y, s, c, sn, ssn, cs, ccs; |
| 469 | mynumber u; |
| 470 | int4 k, m; |
| 471 | double retval = 0; |
| 472 | |
| 473 | #ifndef IN_SINCOS |
| 474 | SET_RESTORE_ROUND_53BIT (FE_TONEAREST); |
| 475 | #endif |
| 476 | |
| 477 | u.x = x; |
| 478 | m = u.i[HIGH_HALF]; |
| 479 | k = 0x7fffffff & m; /* no sign */ |
| 480 | if (k < 0x3e500000) /* if x->0 =>sin(x)=x */ |
| 481 | { |
| 482 | math_check_force_underflow (x); |
| 483 | retval = x; |
| 484 | } |
| 485 | /*---------------------------- 2^-26 < |x|< 0.25 ----------------------*/ |
| 486 | else if (k < 0x3fd00000) |
| 487 | { |
| 488 | xx = x * x; |
| 489 | /* Taylor series. */ |
| 490 | t = POLYNOMIAL (xx) * (xx * x); |
| 491 | res = x + t; |
| 492 | cor = (x - res) + t; |
| 493 | retval = (res == res + 1.07 * cor) ? res : slow (x); |
| 494 | } /* else if (k < 0x3fd00000) */ |
| 495 | /*---------------------------- 0.25<|x|< 0.855469---------------------- */ |
| 496 | else if (k < 0x3feb6000) |
| 497 | { |
| 498 | u.x = (m > 0) ? big + x : big - x; |
| 499 | y = (m > 0) ? x - (u.x - big) : x + (u.x - big); |
| 500 | xx = y * y; |
| 501 | s = y + y * xx * (sn3 + xx * sn5); |
| 502 | c = xx * (cs2 + xx * (cs4 + xx * cs6)); |
| 503 | SINCOS_TABLE_LOOKUP (u, sn, ssn, cs, ccs); |
| 504 | if (m <= 0) |
| 505 | { |
| 506 | sn = -sn; |
| 507 | ssn = -ssn; |
| 508 | } |
| 509 | cor = (ssn + s * ccs - sn * c) + cs * s; |
| 510 | res = sn + cor; |
| 511 | cor = (sn - res) + cor; |
| 512 | retval = (res == res + 1.096 * cor) ? res : slow1 (x); |
| 513 | } /* else if (k < 0x3feb6000) */ |
| 514 | |
| 515 | /*----------------------- 0.855469 <|x|<2.426265 ----------------------*/ |
| 516 | else if (k < 0x400368fd) |
| 517 | { |
| 518 | |
| 519 | y = (m > 0) ? hp0 - x : hp0 + x; |
| 520 | if (y >= 0) |
| 521 | { |
| 522 | u.x = big + y; |
| 523 | y = (y - (u.x - big)) + hp1; |
| 524 | } |
| 525 | else |
| 526 | { |
| 527 | u.x = big - y; |
| 528 | y = (-hp1) - (y + (u.x - big)); |
| 529 | } |
| 530 | res = do_cos (u, y, &cor); |
| 531 | retval = (res == res + 1.020 * cor) ? ((m > 0) ? res : -res) : slow2 (x); |
| 532 | } /* else if (k < 0x400368fd) */ |
| 533 | |
| 534 | #ifndef IN_SINCOS |
| 535 | /*-------------------------- 2.426265<|x|< 105414350 ----------------------*/ |
| 536 | else if (k < 0x419921FB) |
| 537 | { |
| 538 | double a, da; |
| 539 | int4 n = reduce_sincos_1 (x, &a, &da); |
| 540 | retval = do_sincos_1 (a, da, x, n, 0); |
| 541 | } /* else if (k < 0x419921FB ) */ |
| 542 | |
| 543 | /*---------------------105414350 <|x|< 281474976710656 --------------------*/ |
| 544 | else if (k < 0x42F00000) |
| 545 | { |
| 546 | double a, da; |
| 547 | |
| 548 | int4 n = reduce_sincos_2 (x, &a, &da); |
| 549 | retval = do_sincos_2 (a, da, x, n, 0); |
| 550 | } /* else if (k < 0x42F00000 ) */ |
| 551 | |
| 552 | /* -----------------281474976710656 <|x| <2^1024----------------------------*/ |
| 553 | else if (k < 0x7ff00000) |
| 554 | retval = reduce_and_compute (x, 0); |
| 555 | |
| 556 | /*--------------------- |x| > 2^1024 ----------------------------------*/ |
| 557 | else |
| 558 | { |
| 559 | if (k == 0x7ff00000 && u.i[LOW_HALF] == 0) |
| 560 | __set_errno (EDOM); |
| 561 | retval = x / x; |
| 562 | } |
| 563 | #endif |
| 564 | |
| 565 | return retval; |
| 566 | } |
| 567 | |
| 568 | |
| 569 | /*******************************************************************/ |
| 570 | /* An ultimate cos routine. Given an IEEE double machine number x */ |
| 571 | /* it computes the correctly rounded (to nearest) value of cos(x) */ |
| 572 | /*******************************************************************/ |
| 573 | |
| 574 | #ifdef IN_SINCOS |
| 575 | static double |
| 576 | #else |
| 577 | double |
| 578 | SECTION |
| 579 | #endif |
| 580 | __cos (double x) |
| 581 | { |
| 582 | double y, xx, res, cor, a, da; |
| 583 | mynumber u; |
| 584 | int4 k, m; |
| 585 | |
| 586 | double retval = 0; |
| 587 | |
| 588 | #ifndef IN_SINCOS |
| 589 | SET_RESTORE_ROUND_53BIT (FE_TONEAREST); |
| 590 | #endif |
| 591 | |
| 592 | u.x = x; |
| 593 | m = u.i[HIGH_HALF]; |
| 594 | k = 0x7fffffff & m; |
| 595 | |
| 596 | /* |x|<2^-27 => cos(x)=1 */ |
| 597 | if (k < 0x3e400000) |
| 598 | retval = 1.0; |
| 599 | |
| 600 | else if (k < 0x3feb6000) |
| 601 | { /* 2^-27 < |x| < 0.855469 */ |
| 602 | y = fabs (x); |
| 603 | u.x = big + y; |
| 604 | y = y - (u.x - big); |
| 605 | res = do_cos (u, y, &cor); |
| 606 | retval = (res == res + 1.020 * cor) ? res : cslow2 (x); |
| 607 | } /* else if (k < 0x3feb6000) */ |
| 608 | |
| 609 | else if (k < 0x400368fd) |
| 610 | { /* 0.855469 <|x|<2.426265 */ ; |
| 611 | y = hp0 - fabs (x); |
| 612 | a = y + hp1; |
| 613 | da = (y - a) + hp1; |
| 614 | xx = a * a; |
| 615 | if (xx < 0.01588) |
| 616 | { |
| 617 | res = TAYLOR_SIN (xx, a, da, cor); |
| 618 | cor = (cor > 0) ? 1.02 * cor + 1.0e-31 : 1.02 * cor - 1.0e-31; |
| 619 | retval = (res == res + cor) ? res : sloww (a, da, x, 1); |
| 620 | } |
| 621 | else |
| 622 | { |
| 623 | if (a > 0) |
| 624 | { |
| 625 | m = 1; |
| 626 | } |
| 627 | else |
| 628 | { |
| 629 | m = 0; |
| 630 | a = -a; |
| 631 | da = -da; |
| 632 | } |
| 633 | u.x = big + a; |
| 634 | y = a - (u.x - big); |
| 635 | res = do_sin (u, y, da, &cor); |
| 636 | cor = (cor > 0) ? 1.035 * cor + 1.0e-31 : 1.035 * cor - 1.0e-31; |
| 637 | retval = ((res == res + cor) ? ((m) ? res : -res) |
| 638 | : sloww1 (a, da, x, m, 1)); |
| 639 | } |
| 640 | |
| 641 | } /* else if (k < 0x400368fd) */ |
| 642 | |
| 643 | |
| 644 | #ifndef IN_SINCOS |
| 645 | else if (k < 0x419921FB) |
| 646 | { /* 2.426265<|x|< 105414350 */ |
| 647 | double a, da; |
| 648 | int4 n = reduce_sincos_1 (x, &a, &da); |
| 649 | retval = do_sincos_1 (a, da, x, n, 1); |
| 650 | } /* else if (k < 0x419921FB ) */ |
| 651 | |
| 652 | else if (k < 0x42F00000) |
| 653 | { |
| 654 | double a, da; |
| 655 | |
| 656 | int4 n = reduce_sincos_2 (x, &a, &da); |
| 657 | retval = do_sincos_2 (a, da, x, n, 1); |
| 658 | } /* else if (k < 0x42F00000 ) */ |
| 659 | |
| 660 | /* 281474976710656 <|x| <2^1024 */ |
| 661 | else if (k < 0x7ff00000) |
| 662 | retval = reduce_and_compute (x, 1); |
| 663 | |
| 664 | else |
| 665 | { |
| 666 | if (k == 0x7ff00000 && u.i[LOW_HALF] == 0) |
| 667 | __set_errno (EDOM); |
| 668 | retval = x / x; /* |x| > 2^1024 */ |
| 669 | } |
| 670 | #endif |
| 671 | |
| 672 | return retval; |
| 673 | } |
| 674 | |
| 675 | /************************************************************************/ |
| 676 | /* Routine compute sin(x) for 2^-26 < |x|< 0.25 by Taylor with more */ |
| 677 | /* precision and if still doesn't accurate enough by mpsin or dubsin */ |
| 678 | /************************************************************************/ |
| 679 | |
| 680 | static double |
| 681 | SECTION |
| 682 | slow (double x) |
| 683 | { |
| 684 | double res, cor, w[2]; |
| 685 | res = TAYLOR_SLOW (x, 0, cor); |
| 686 | if (res == res + 1.0007 * cor) |
| 687 | return res; |
| 688 | |
| 689 | __dubsin (fabs (x), 0, w); |
| 690 | if (w[0] == w[0] + 1.000000001 * w[1]) |
| 691 | return (x > 0) ? w[0] : -w[0]; |
| 692 | |
| 693 | return (x > 0) ? __mpsin (x, 0, false) : -__mpsin (-x, 0, false); |
| 694 | } |
| 695 | |
| 696 | /*******************************************************************************/ |
| 697 | /* Routine compute sin(x) for 0.25<|x|< 0.855469 by __sincostab.tbl and Taylor */ |
| 698 | /* and if result still doesn't accurate enough by mpsin or dubsin */ |
| 699 | /*******************************************************************************/ |
| 700 | |
| 701 | static double |
| 702 | SECTION |
| 703 | slow1 (double x) |
| 704 | { |
| 705 | mynumber u; |
| 706 | double w[2], y, cor, res; |
| 707 | y = fabs (x); |
| 708 | u.x = big + y; |
| 709 | y = y - (u.x - big); |
| 710 | res = do_sin_slow (u, y, 0, 0, &cor); |
| 711 | if (res == res + cor) |
| 712 | return (x > 0) ? res : -res; |
| 713 | |
| 714 | __dubsin (fabs (x), 0, w); |
| 715 | if (w[0] == w[0] + 1.000000005 * w[1]) |
| 716 | return (x > 0) ? w[0] : -w[0]; |
| 717 | |
| 718 | return (x > 0) ? __mpsin (x, 0, false) : -__mpsin (-x, 0, false); |
| 719 | } |
| 720 | |
| 721 | /**************************************************************************/ |
| 722 | /* Routine compute sin(x) for 0.855469 <|x|<2.426265 by __sincostab.tbl */ |
| 723 | /* and if result still doesn't accurate enough by mpsin or dubsin */ |
| 724 | /**************************************************************************/ |
| 725 | static double |
| 726 | SECTION |
| 727 | slow2 (double x) |
| 728 | { |
| 729 | mynumber u; |
| 730 | double w[2], y, y1, y2, cor, res, del; |
| 731 | |
| 732 | y = fabs (x); |
| 733 | y = hp0 - y; |
| 734 | if (y >= 0) |
| 735 | { |
| 736 | u.x = big + y; |
| 737 | y = y - (u.x - big); |
| 738 | del = hp1; |
| 739 | } |
| 740 | else |
| 741 | { |
| 742 | u.x = big - y; |
| 743 | y = -(y + (u.x - big)); |
| 744 | del = -hp1; |
| 745 | } |
| 746 | res = do_cos_slow (u, y, del, 0, &cor); |
| 747 | if (res == res + cor) |
| 748 | return (x > 0) ? res : -res; |
| 749 | |
| 750 | y = fabs (x) - hp0; |
| 751 | y1 = y - hp1; |
| 752 | y2 = (y - y1) - hp1; |
| 753 | __docos (y1, y2, w); |
| 754 | if (w[0] == w[0] + 1.000000005 * w[1]) |
| 755 | return (x > 0) ? w[0] : -w[0]; |
| 756 | |
| 757 | return (x > 0) ? __mpsin (x, 0, false) : -__mpsin (-x, 0, false); |
| 758 | } |
| 759 | |
| 760 | /***************************************************************************/ |
| 761 | /* Routine compute sin(x+dx) (Double-Length number) where x is small enough*/ |
| 762 | /* to use Taylor series around zero and (x+dx) */ |
| 763 | /* in first or third quarter of unit circle.Routine receive also */ |
| 764 | /* (right argument) the original value of x for computing error of */ |
| 765 | /* result.And if result not accurate enough routine calls mpsin1 or dubsin */ |
| 766 | /***************************************************************************/ |
| 767 | |
| 768 | static double |
| 769 | SECTION |
| 770 | sloww (double x, double dx, double orig, int k) |
| 771 | { |
| 772 | double y, t, res, cor, w[2], a, da, xn; |
| 773 | mynumber v; |
| 774 | int4 n; |
| 775 | res = TAYLOR_SLOW (x, dx, cor); |
| 776 | |
| 777 | if (cor > 0) |
| 778 | cor = 1.0005 * cor + fabs (orig) * 3.1e-30; |
| 779 | else |
| 780 | cor = 1.0005 * cor - fabs (orig) * 3.1e-30; |
| 781 | |
| 782 | if (res == res + cor) |
| 783 | return res; |
| 784 | |
| 785 | (x > 0) ? __dubsin (x, dx, w) : __dubsin (-x, -dx, w); |
| 786 | if (w[1] > 0) |
| 787 | cor = 1.000000001 * w[1] + fabs (orig) * 1.1e-30; |
| 788 | else |
| 789 | cor = 1.000000001 * w[1] - fabs (orig) * 1.1e-30; |
| 790 | |
| 791 | if (w[0] == w[0] + cor) |
| 792 | return (x > 0) ? w[0] : -w[0]; |
| 793 | |
| 794 | t = (orig * hpinv + toint); |
| 795 | xn = t - toint; |
| 796 | v.x = t; |
| 797 | y = (orig - xn * mp1) - xn * mp2; |
| 798 | n = (v.i[LOW_HALF] + k) & 3; |
| 799 | da = xn * pp3; |
| 800 | t = y - da; |
| 801 | da = (y - t) - da; |
| 802 | y = xn * pp4; |
| 803 | a = t - y; |
| 804 | da = ((t - a) - y) + da; |
| 805 | |
| 806 | if (n == 2 || n == 1) |
| 807 | { |
| 808 | a = -a; |
| 809 | da = -da; |
| 810 | } |
| 811 | (a > 0) ? __dubsin (a, da, w) : __dubsin (-a, -da, w); |
| 812 | if (w[1] > 0) |
| 813 | cor = 1.000000001 * w[1] + fabs (orig) * 1.1e-40; |
| 814 | else |
| 815 | cor = 1.000000001 * w[1] - fabs (orig) * 1.1e-40; |
| 816 | |
| 817 | if (w[0] == w[0] + cor) |
| 818 | return (a > 0) ? w[0] : -w[0]; |
| 819 | |
| 820 | return (n & 1) ? __mpcos (orig, 0, true) : __mpsin (orig, 0, true); |
| 821 | } |
| 822 | |
| 823 | /***************************************************************************/ |
| 824 | /* Routine compute sin(x+dx) (Double-Length number) where x in first or */ |
| 825 | /* third quarter of unit circle.Routine receive also (right argument) the */ |
| 826 | /* original value of x for computing error of result.And if result not */ |
| 827 | /* accurate enough routine calls mpsin1 or dubsin */ |
| 828 | /***************************************************************************/ |
| 829 | |
| 830 | static double |
| 831 | SECTION |
| 832 | sloww1 (double x, double dx, double orig, int m, int k) |
| 833 | { |
| 834 | mynumber u; |
| 835 | double w[2], y, cor, res; |
| 836 | |
| 837 | u.x = big + x; |
| 838 | y = x - (u.x - big); |
| 839 | res = do_sin_slow (u, y, dx, 3.1e-30 * fabs (orig), &cor); |
| 840 | |
| 841 | if (res == res + cor) |
| 842 | return (m > 0) ? res : -res; |
| 843 | |
| 844 | __dubsin (x, dx, w); |
| 845 | |
| 846 | if (w[1] > 0) |
| 847 | cor = 1.000000005 * w[1] + 1.1e-30 * fabs (orig); |
| 848 | else |
| 849 | cor = 1.000000005 * w[1] - 1.1e-30 * fabs (orig); |
| 850 | |
| 851 | if (w[0] == w[0] + cor) |
| 852 | return (m > 0) ? w[0] : -w[0]; |
| 853 | |
| 854 | return (k == 1) ? __mpcos (orig, 0, true) : __mpsin (orig, 0, true); |
| 855 | } |
| 856 | |
| 857 | /***************************************************************************/ |
| 858 | /* Routine compute sin(x+dx) (Double-Length number) where x in second or */ |
| 859 | /* fourth quarter of unit circle.Routine receive also the original value */ |
| 860 | /* and quarter(n= 1or 3)of x for computing error of result.And if result not*/ |
| 861 | /* accurate enough routine calls mpsin1 or dubsin */ |
| 862 | /***************************************************************************/ |
| 863 | |
| 864 | static double |
| 865 | SECTION |
| 866 | sloww2 (double x, double dx, double orig, int n) |
| 867 | { |
| 868 | mynumber u; |
| 869 | double w[2], y, cor, res; |
| 870 | |
| 871 | u.x = big + x; |
| 872 | y = x - (u.x - big); |
| 873 | res = do_cos_slow (u, y, dx, 3.1e-30 * fabs (orig), &cor); |
| 874 | |
| 875 | if (res == res + cor) |
| 876 | return (n & 2) ? -res : res; |
| 877 | |
| 878 | __docos (x, dx, w); |
| 879 | |
| 880 | if (w[1] > 0) |
| 881 | cor = 1.000000005 * w[1] + 1.1e-30 * fabs (orig); |
| 882 | else |
| 883 | cor = 1.000000005 * w[1] - 1.1e-30 * fabs (orig); |
| 884 | |
| 885 | if (w[0] == w[0] + cor) |
| 886 | return (n & 2) ? -w[0] : w[0]; |
| 887 | |
| 888 | return (n & 1) ? __mpsin (orig, 0, true) : __mpcos (orig, 0, true); |
| 889 | } |
| 890 | |
| 891 | /***************************************************************************/ |
| 892 | /* Routine compute sin(x+dx) or cos(x+dx) (Double-Length number) where x */ |
| 893 | /* is small enough to use Taylor series around zero and (x+dx) */ |
| 894 | /* in first or third quarter of unit circle.Routine receive also */ |
| 895 | /* (right argument) the original value of x for computing error of */ |
| 896 | /* result.And if result not accurate enough routine calls other routines */ |
| 897 | /***************************************************************************/ |
| 898 | |
| 899 | static double |
| 900 | SECTION |
| 901 | bsloww (double x, double dx, double orig, int n) |
| 902 | { |
| 903 | double res, cor, w[2]; |
| 904 | |
| 905 | res = TAYLOR_SLOW (x, dx, cor); |
| 906 | cor = (cor > 0) ? 1.0005 * cor + 1.1e-24 : 1.0005 * cor - 1.1e-24; |
| 907 | if (res == res + cor) |
| 908 | return res; |
| 909 | |
| 910 | (x > 0) ? __dubsin (x, dx, w) : __dubsin (-x, -dx, w); |
| 911 | if (w[1] > 0) |
| 912 | cor = 1.000000001 * w[1] + 1.1e-24; |
| 913 | else |
| 914 | cor = 1.000000001 * w[1] - 1.1e-24; |
| 915 | |
| 916 | if (w[0] == w[0] + cor) |
| 917 | return (x > 0) ? w[0] : -w[0]; |
| 918 | |
| 919 | return (n & 1) ? __mpcos (orig, 0, true) : __mpsin (orig, 0, true); |
| 920 | } |
| 921 | |
| 922 | /***************************************************************************/ |
| 923 | /* Routine compute sin(x+dx) or cos(x+dx) (Double-Length number) where x */ |
| 924 | /* in first or third quarter of unit circle.Routine receive also */ |
| 925 | /* (right argument) the original value of x for computing error of result.*/ |
| 926 | /* And if result not accurate enough routine calls other routines */ |
| 927 | /***************************************************************************/ |
| 928 | |
| 929 | static double |
| 930 | SECTION |
| 931 | bsloww1 (double x, double dx, double orig, int n) |
| 932 | { |
| 933 | mynumber u; |
| 934 | double w[2], y, cor, res; |
| 935 | |
| 936 | y = fabs (x); |
| 937 | u.x = big + y; |
| 938 | y = y - (u.x - big); |
| 939 | dx = (x > 0) ? dx : -dx; |
| 940 | res = do_sin_slow (u, y, dx, 1.1e-24, &cor); |
| 941 | if (res == res + cor) |
| 942 | return (x > 0) ? res : -res; |
| 943 | |
| 944 | __dubsin (fabs (x), dx, w); |
| 945 | |
| 946 | if (w[1] > 0) |
| 947 | cor = 1.000000005 * w[1] + 1.1e-24; |
| 948 | else |
| 949 | cor = 1.000000005 * w[1] - 1.1e-24; |
| 950 | |
| 951 | if (w[0] == w[0] + cor) |
| 952 | return (x > 0) ? w[0] : -w[0]; |
| 953 | |
| 954 | return (n & 1) ? __mpcos (orig, 0, true) : __mpsin (orig, 0, true); |
| 955 | } |
| 956 | |
| 957 | /***************************************************************************/ |
| 958 | /* Routine compute sin(x+dx) or cos(x+dx) (Double-Length number) where x */ |
| 959 | /* in second or fourth quarter of unit circle.Routine receive also the */ |
| 960 | /* original value and quarter(n= 1or 3)of x for computing error of result. */ |
| 961 | /* And if result not accurate enough routine calls other routines */ |
| 962 | /***************************************************************************/ |
| 963 | |
| 964 | static double |
| 965 | SECTION |
| 966 | bsloww2 (double x, double dx, double orig, int n) |
| 967 | { |
| 968 | mynumber u; |
| 969 | double w[2], y, cor, res; |
| 970 | |
| 971 | y = fabs (x); |
| 972 | u.x = big + y; |
| 973 | y = y - (u.x - big); |
| 974 | dx = (x > 0) ? dx : -dx; |
| 975 | res = do_cos_slow (u, y, dx, 1.1e-24, &cor); |
| 976 | if (res == res + cor) |
| 977 | return (n & 2) ? -res : res; |
| 978 | |
| 979 | __docos (fabs (x), dx, w); |
| 980 | |
| 981 | if (w[1] > 0) |
| 982 | cor = 1.000000005 * w[1] + 1.1e-24; |
| 983 | else |
| 984 | cor = 1.000000005 * w[1] - 1.1e-24; |
| 985 | |
| 986 | if (w[0] == w[0] + cor) |
| 987 | return (n & 2) ? -w[0] : w[0]; |
| 988 | |
| 989 | return (n & 1) ? __mpsin (orig, 0, true) : __mpcos (orig, 0, true); |
| 990 | } |
| 991 | |
| 992 | /************************************************************************/ |
| 993 | /* Routine compute cos(x) for 2^-27 < |x|< 0.25 by Taylor with more */ |
| 994 | /* precision and if still doesn't accurate enough by mpcos or docos */ |
| 995 | /************************************************************************/ |
| 996 | |
| 997 | static double |
| 998 | SECTION |
| 999 | cslow2 (double x) |
| 1000 | { |
| 1001 | mynumber u; |
| 1002 | double w[2], y, cor, res; |
| 1003 | |
| 1004 | y = fabs (x); |
| 1005 | u.x = big + y; |
| 1006 | y = y - (u.x - big); |
| 1007 | res = do_cos_slow (u, y, 0, 0, &cor); |
| 1008 | if (res == res + cor) |
| 1009 | return res; |
| 1010 | |
| 1011 | y = fabs (x); |
| 1012 | __docos (y, 0, w); |
| 1013 | if (w[0] == w[0] + 1.000000005 * w[1]) |
| 1014 | return w[0]; |
| 1015 | |
| 1016 | return __mpcos (x, 0, false); |
| 1017 | } |
| 1018 | |
| 1019 | #ifndef __cos |
| 1020 | weak_alias (__cos, cos) |
| 1021 | # ifdef NO_LONG_DOUBLE |
| 1022 | strong_alias (__cos, __cosl) |
| 1023 | weak_alias (__cos, cosl) |
| 1024 | # endif |
| 1025 | #endif |
| 1026 | #ifndef __sin |
| 1027 | weak_alias (__sin, sin) |
| 1028 | # ifdef NO_LONG_DOUBLE |
| 1029 | strong_alias (__sin, __sinl) |
| 1030 | weak_alias (__sin, sinl) |
| 1031 | # endif |
| 1032 | #endif |
| 1033 | |