2 * Ported from a work by Andreas Grabher for Previous, NeXT Computer Emulator,
3 * derived from NetBSD M68040 FPSP functions,
4 * derived from release 2a of the SoftFloat IEC/IEEE Floating-point Arithmetic
5 * Package. Those parts of the code (and some later contributions) are
6 * provided under that license, as detailed below.
7 * It has subsequently been modified by contributors to the QEMU Project,
8 * so some portions are provided under:
9 * the SoftFloat-2a license
13 * Any future contributions to this file will be taken to be licensed under
14 * the Softfloat-2a license unless specifically indicated otherwise.
17 /* Portions of this work are licensed under the terms of the GNU GPL,
18 * version 2 or later. See the COPYING file in the top-level directory.
21 #include "qemu/osdep.h"
22 #include "softfloat.h"
23 #include "fpu/softfloat-macros.h"
24 #include "softfloat_fpsp_tables.h"
27 #define piby2_exp 0x3FFF
28 #define pi_sig LIT64(0xc90fdaa22168c235)
30 static floatx80 propagateFloatx80NaNOneArg(floatx80 a, float_status *status)
32 if (floatx80_is_signaling_nan(a, status)) {
33 float_raise(float_flag_invalid, status);
36 if (status->default_nan_mode) {
37 return floatx80_default_nan(status);
40 return floatx80_maybe_silence_nan(a, status);
43 /*----------------------------------------------------------------------------
44 | Returns the modulo remainder of the extended double-precision floating-point
45 | value `a' with respect to the corresponding value `b'.
46 *----------------------------------------------------------------------------*/
48 floatx80 floatx80_mod(floatx80 a, floatx80 b, float_status *status)
51 int32_t aExp, bExp, expDiff;
52 uint64_t aSig0, aSig1, bSig;
53 uint64_t qTemp, term0, term1;
55 aSig0 = extractFloatx80Frac(a);
56 aExp = extractFloatx80Exp(a);
57 aSign = extractFloatx80Sign(a);
58 bSig = extractFloatx80Frac(b);
59 bExp = extractFloatx80Exp(b);
62 if ((uint64_t) (aSig0 << 1)
63 || ((bExp == 0x7FFF) && (uint64_t) (bSig << 1))) {
64 return propagateFloatx80NaN(a, b, status);
69 if ((uint64_t) (bSig << 1)) {
70 return propagateFloatx80NaN(a, b, status);
77 float_raise(float_flag_invalid, status);
78 return floatx80_default_nan(status);
80 normalizeFloatx80Subnormal(bSig, &bExp, &bSig);
83 if ((uint64_t) (aSig0 << 1) == 0) {
86 normalizeFloatx80Subnormal(aSig0, &aExp, &aSig0);
88 bSig |= LIT64(0x8000000000000000);
90 expDiff = aExp - bExp;
95 qTemp = (bSig <= aSig0);
100 while (0 < expDiff) {
101 qTemp = estimateDiv128To64(aSig0, aSig1, bSig);
102 qTemp = (2 < qTemp) ? qTemp - 2 : 0;
103 mul64To128(bSig, qTemp, &term0, &term1);
104 sub128(aSig0, aSig1, term0, term1, &aSig0, &aSig1);
105 shortShift128Left(aSig0, aSig1, 62, &aSig0, &aSig1);
110 qTemp = estimateDiv128To64(aSig0, aSig1, bSig);
111 qTemp = (2 < qTemp) ? qTemp - 2 : 0;
112 qTemp >>= 64 - expDiff;
113 mul64To128(bSig, qTemp << (64 - expDiff), &term0, &term1);
114 sub128(aSig0, aSig1, term0, term1, &aSig0, &aSig1);
115 shortShift128Left(0, bSig, 64 - expDiff, &term0, &term1);
116 while (le128(term0, term1, aSig0, aSig1)) {
118 sub128(aSig0, aSig1, term0, term1, &aSig0, &aSig1);
122 normalizeRoundAndPackFloatx80(
123 80, zSign, bExp + expDiff, aSig0, aSig1, status);
126 /*----------------------------------------------------------------------------
127 | Returns the mantissa of the extended double-precision floating-point
129 *----------------------------------------------------------------------------*/
131 floatx80 floatx80_getman(floatx80 a, float_status *status)
137 aSig = extractFloatx80Frac(a);
138 aExp = extractFloatx80Exp(a);
139 aSign = extractFloatx80Sign(a);
141 if (aExp == 0x7FFF) {
142 if ((uint64_t) (aSig << 1)) {
143 return propagateFloatx80NaNOneArg(a , status);
145 float_raise(float_flag_invalid , status);
146 return floatx80_default_nan(status);
151 return packFloatx80(aSign, 0, 0);
153 normalizeFloatx80Subnormal(aSig, &aExp, &aSig);
156 return roundAndPackFloatx80(status->floatx80_rounding_precision, aSign,
157 0x3FFF, aSig, 0, status);
160 /*----------------------------------------------------------------------------
161 | Returns the exponent of the extended double-precision floating-point
162 | value `a' as an extended double-precision value.
163 *----------------------------------------------------------------------------*/
165 floatx80 floatx80_getexp(floatx80 a, float_status *status)
171 aSig = extractFloatx80Frac(a);
172 aExp = extractFloatx80Exp(a);
173 aSign = extractFloatx80Sign(a);
175 if (aExp == 0x7FFF) {
176 if ((uint64_t) (aSig << 1)) {
177 return propagateFloatx80NaNOneArg(a , status);
179 float_raise(float_flag_invalid , status);
180 return floatx80_default_nan(status);
185 return packFloatx80(aSign, 0, 0);
187 normalizeFloatx80Subnormal(aSig, &aExp, &aSig);
190 return int32_to_floatx80(aExp - 0x3FFF, status);
193 /*----------------------------------------------------------------------------
194 | Scales extended double-precision floating-point value in operand `a' by
195 | value `b'. The function truncates the value in the second operand 'b' to
196 | an integral value and adds that value to the exponent of the operand 'a'.
197 | The operation performed according to the IEC/IEEE Standard for Binary
198 | Floating-Point Arithmetic.
199 *----------------------------------------------------------------------------*/
201 floatx80 floatx80_scale(floatx80 a, floatx80 b, float_status *status)
204 int32_t aExp, bExp, shiftCount;
207 aSig = extractFloatx80Frac(a);
208 aExp = extractFloatx80Exp(a);
209 aSign = extractFloatx80Sign(a);
210 bSig = extractFloatx80Frac(b);
211 bExp = extractFloatx80Exp(b);
212 bSign = extractFloatx80Sign(b);
214 if (bExp == 0x7FFF) {
215 if ((uint64_t) (bSig << 1) ||
216 ((aExp == 0x7FFF) && (uint64_t) (aSig << 1))) {
217 return propagateFloatx80NaN(a, b, status);
219 float_raise(float_flag_invalid , status);
220 return floatx80_default_nan(status);
222 if (aExp == 0x7FFF) {
223 if ((uint64_t) (aSig << 1)) {
224 return propagateFloatx80NaN(a, b, status);
226 return packFloatx80(aSign, floatx80_infinity.high,
227 floatx80_infinity.low);
231 return packFloatx80(aSign, 0, 0);
236 normalizeFloatx80Subnormal(aSig, &aExp, &aSig);
244 aExp = bSign ? -0x6001 : 0xE000;
245 return roundAndPackFloatx80(status->floatx80_rounding_precision,
246 aSign, aExp, aSig, 0, status);
249 shiftCount = 0x403E - bExp;
251 aExp = bSign ? (aExp - bSig) : (aExp + bSig);
253 return roundAndPackFloatx80(status->floatx80_rounding_precision,
254 aSign, aExp, aSig, 0, status);
257 floatx80 floatx80_move(floatx80 a, float_status *status)
263 aSig = extractFloatx80Frac(a);
264 aExp = extractFloatx80Exp(a);
265 aSign = extractFloatx80Sign(a);
267 if (aExp == 0x7FFF) {
268 if ((uint64_t)(aSig << 1)) {
269 return propagateFloatx80NaNOneArg(a, status);
277 normalizeRoundAndPackFloatx80(status->floatx80_rounding_precision,
278 aSign, aExp, aSig, 0, status);
280 return roundAndPackFloatx80(status->floatx80_rounding_precision, aSign,
281 aExp, aSig, 0, status);
284 /*----------------------------------------------------------------------------
285 | Algorithms for transcendental functions supported by MC68881 and MC68882
286 | mathematical coprocessors. The functions are derived from FPSP library.
287 *----------------------------------------------------------------------------*/
289 #define one_exp 0x3FFF
290 #define one_sig LIT64(0x8000000000000000)
292 /*----------------------------------------------------------------------------
293 | Function for compactifying extended double-precision floating point values.
294 *----------------------------------------------------------------------------*/
296 static int32_t floatx80_make_compact(int32_t aExp, uint64_t aSig)
298 return (aExp << 16) | (aSig >> 48);
301 /*----------------------------------------------------------------------------
302 | Log base e of x plus 1
303 *----------------------------------------------------------------------------*/
305 floatx80 floatx80_lognp1(floatx80 a, float_status *status)
311 int8_t user_rnd_mode, user_rnd_prec;
313 int32_t compact, j, k;
314 floatx80 fp0, fp1, fp2, fp3, f, logof2, klog2, saveu;
316 aSig = extractFloatx80Frac(a);
317 aExp = extractFloatx80Exp(a);
318 aSign = extractFloatx80Sign(a);
320 if (aExp == 0x7FFF) {
321 if ((uint64_t) (aSig << 1)) {
322 propagateFloatx80NaNOneArg(a, status);
325 float_raise(float_flag_invalid, status);
326 return floatx80_default_nan(status);
328 return packFloatx80(0, floatx80_infinity.high, floatx80_infinity.low);
331 if (aExp == 0 && aSig == 0) {
332 return packFloatx80(aSign, 0, 0);
335 if (aSign && aExp >= one_exp) {
336 if (aExp == one_exp && aSig == one_sig) {
337 float_raise(float_flag_divbyzero, status);
338 return packFloatx80(aSign, floatx80_infinity.high,
339 floatx80_infinity.low);
341 float_raise(float_flag_invalid, status);
342 return floatx80_default_nan(status);
345 if (aExp < 0x3f99 || (aExp == 0x3f99 && aSig == one_sig)) {
346 /* <= min threshold */
347 float_raise(float_flag_inexact, status);
348 return floatx80_move(a, status);
351 user_rnd_mode = status->float_rounding_mode;
352 user_rnd_prec = status->floatx80_rounding_precision;
353 status->float_rounding_mode = float_round_nearest_even;
354 status->floatx80_rounding_precision = 80;
356 compact = floatx80_make_compact(aExp, aSig);
361 fp0 = floatx80_add(fp0, float32_to_floatx80(make_float32(0x3F800000),
362 status), status); /* X = (1+Z) */
364 aExp = extractFloatx80Exp(fp0);
365 aSig = extractFloatx80Frac(fp0);
367 compact = floatx80_make_compact(aExp, aSig);
369 if (compact < 0x3FFE8000 || compact > 0x3FFFC000) {
370 /* |X| < 1/2 or |X| > 3/2 */
372 fp1 = int32_to_floatx80(k, status);
374 fSig = (aSig & LIT64(0xFE00000000000000)) | LIT64(0x0100000000000000);
375 j = (fSig >> 56) & 0x7E; /* DISPLACEMENT FOR 1/F */
377 f = packFloatx80(0, 0x3FFF, fSig); /* F */
378 fp0 = packFloatx80(0, 0x3FFF, aSig); /* Y */
380 fp0 = floatx80_sub(fp0, f, status); /* Y-F */
384 fp0 = floatx80_mul(fp0, log_tbl[j], status); /* FP0 IS U = (Y-F)/F */
385 logof2 = packFloatx80(0, 0x3FFE, LIT64(0xB17217F7D1CF79AC));
386 klog2 = floatx80_mul(fp1, logof2, status); /* FP1 IS K*LOG2 */
387 fp2 = floatx80_mul(fp0, fp0, status); /* FP2 IS V=U*U */
392 fp1 = floatx80_mul(fp1, float64_to_floatx80(
393 make_float64(0x3FC2499AB5E4040B), status),
395 fp2 = floatx80_mul(fp2, float64_to_floatx80(
396 make_float64(0xBFC555B5848CB7DB), status),
398 fp1 = floatx80_add(fp1, float64_to_floatx80(
399 make_float64(0x3FC99999987D8730), status),
400 status); /* A4+V*A6 */
401 fp2 = floatx80_add(fp2, float64_to_floatx80(
402 make_float64(0xBFCFFFFFFF6F7E97), status),
403 status); /* A3+V*A5 */
404 fp1 = floatx80_mul(fp1, fp3, status); /* V*(A4+V*A6) */
405 fp2 = floatx80_mul(fp2, fp3, status); /* V*(A3+V*A5) */
406 fp1 = floatx80_add(fp1, float64_to_floatx80(
407 make_float64(0x3FD55555555555A4), status),
408 status); /* A2+V*(A4+V*A6) */
409 fp2 = floatx80_add(fp2, float64_to_floatx80(
410 make_float64(0xBFE0000000000008), status),
411 status); /* A1+V*(A3+V*A5) */
412 fp1 = floatx80_mul(fp1, fp3, status); /* V*(A2+V*(A4+V*A6)) */
413 fp2 = floatx80_mul(fp2, fp3, status); /* V*(A1+V*(A3+V*A5)) */
414 fp1 = floatx80_mul(fp1, fp0, status); /* U*V*(A2+V*(A4+V*A6)) */
415 fp0 = floatx80_add(fp0, fp2, status); /* U+V*(A1+V*(A3+V*A5)) */
417 fp1 = floatx80_add(fp1, log_tbl[j + 1],
418 status); /* LOG(F)+U*V*(A2+V*(A4+V*A6)) */
419 fp0 = floatx80_add(fp0, fp1, status); /* FP0 IS LOG(F) + LOG(1+U) */
421 status->float_rounding_mode = user_rnd_mode;
422 status->floatx80_rounding_precision = user_rnd_prec;
424 a = floatx80_add(fp0, klog2, status);
426 float_raise(float_flag_inexact, status);
429 } else if (compact < 0x3FFEF07D || compact > 0x3FFF8841) {
430 /* |X| < 1/16 or |X| > -1/16 */
432 fSig = (aSig & LIT64(0xFE00000000000000)) | LIT64(0x0100000000000000);
433 f = packFloatx80(0, 0x3FFF, fSig); /* F */
434 j = (fSig >> 56) & 0x7E; /* DISPLACEMENT FOR 1/F */
436 if (compact >= 0x3FFF8000) { /* 1+Z >= 1 */
438 fp0 = floatx80_sub(float32_to_floatx80(make_float32(0x3F800000),
439 status), f, status); /* 1-F */
440 fp0 = floatx80_add(fp0, fp1, status); /* FP0 IS Y-F = (1-F)+Z */
441 fp1 = packFloatx80(0, 0, 0); /* K = 0 */
444 fp0 = floatx80_sub(float32_to_floatx80(make_float32(0x40000000),
445 status), f, status); /* 2-F */
446 fp1 = floatx80_add(fp1, fp1, status); /* 2Z */
447 fp0 = floatx80_add(fp0, fp1, status); /* FP0 IS Y-F = (2-F)+2Z */
448 fp1 = packFloatx80(1, one_exp, one_sig); /* K = -1 */
453 fp1 = floatx80_add(fp1, fp1, status); /* FP1 IS 2Z */
454 fp0 = floatx80_add(fp0, float32_to_floatx80(make_float32(0x3F800000),
455 status), status); /* FP0 IS 1+X */
458 fp1 = floatx80_div(fp1, fp0, status); /* U */
460 fp0 = floatx80_mul(fp1, fp1, status); /* FP0 IS V = U*U */
461 fp1 = floatx80_mul(fp0, fp0, status); /* FP1 IS W = V*V */
463 fp3 = float64_to_floatx80(make_float64(0x3F175496ADD7DAD6),
465 fp2 = float64_to_floatx80(make_float64(0x3F3C71C2FE80C7E0),
467 fp3 = floatx80_mul(fp3, fp1, status); /* W*B5 */
468 fp2 = floatx80_mul(fp2, fp1, status); /* W*B4 */
469 fp3 = floatx80_add(fp3, float64_to_floatx80(
470 make_float64(0x3F624924928BCCFF), status),
471 status); /* B3+W*B5 */
472 fp2 = floatx80_add(fp2, float64_to_floatx80(
473 make_float64(0x3F899999999995EC), status),
474 status); /* B2+W*B4 */
475 fp1 = floatx80_mul(fp1, fp3, status); /* W*(B3+W*B5) */
476 fp2 = floatx80_mul(fp2, fp0, status); /* V*(B2+W*B4) */
477 fp1 = floatx80_add(fp1, float64_to_floatx80(
478 make_float64(0x3FB5555555555555), status),
479 status); /* B1+W*(B3+W*B5) */
481 fp0 = floatx80_mul(fp0, saveu, status); /* FP0 IS U*V */
482 fp1 = floatx80_add(fp1, fp2,
483 status); /* B1+W*(B3+W*B5) + V*(B2+W*B4) */
484 fp0 = floatx80_mul(fp0, fp1,
485 status); /* U*V*([B1+W*(B3+W*B5)] + [V*(B2+W*B4)]) */
487 status->float_rounding_mode = user_rnd_mode;
488 status->floatx80_rounding_precision = user_rnd_prec;
490 a = floatx80_add(fp0, saveu, status);
492 /*if (!floatx80_is_zero(a)) { */
493 float_raise(float_flag_inexact, status);
500 /*----------------------------------------------------------------------------
502 *----------------------------------------------------------------------------*/
504 floatx80 floatx80_logn(floatx80 a, float_status *status)
510 int8_t user_rnd_mode, user_rnd_prec;
512 int32_t compact, j, k, adjk;
513 floatx80 fp0, fp1, fp2, fp3, f, logof2, klog2, saveu;
515 aSig = extractFloatx80Frac(a);
516 aExp = extractFloatx80Exp(a);
517 aSign = extractFloatx80Sign(a);
519 if (aExp == 0x7FFF) {
520 if ((uint64_t) (aSig << 1)) {
521 propagateFloatx80NaNOneArg(a, status);
524 return packFloatx80(0, floatx80_infinity.high,
525 floatx80_infinity.low);
532 if (aSig == 0) { /* zero */
533 float_raise(float_flag_divbyzero, status);
534 return packFloatx80(1, floatx80_infinity.high,
535 floatx80_infinity.low);
537 if ((aSig & one_sig) == 0) { /* denormal */
538 normalizeFloatx80Subnormal(aSig, &aExp, &aSig);
541 a = packFloatx80(aSign, aExp, aSig);
546 float_raise(float_flag_invalid, status);
547 return floatx80_default_nan(status);
550 user_rnd_mode = status->float_rounding_mode;
551 user_rnd_prec = status->floatx80_rounding_precision;
552 status->float_rounding_mode = float_round_nearest_even;
553 status->floatx80_rounding_precision = 80;
555 compact = floatx80_make_compact(aExp, aSig);
557 if (compact < 0x3FFEF07D || compact > 0x3FFF8841) {
558 /* |X| < 15/16 or |X| > 17/16 */
561 fp1 = int32_to_floatx80(k, status);
563 fSig = (aSig & LIT64(0xFE00000000000000)) | LIT64(0x0100000000000000);
564 j = (fSig >> 56) & 0x7E; /* DISPLACEMENT FOR 1/F */
566 f = packFloatx80(0, 0x3FFF, fSig); /* F */
567 fp0 = packFloatx80(0, 0x3FFF, aSig); /* Y */
569 fp0 = floatx80_sub(fp0, f, status); /* Y-F */
572 fp0 = floatx80_mul(fp0, log_tbl[j], status); /* FP0 IS U = (Y-F)/F */
573 logof2 = packFloatx80(0, 0x3FFE, LIT64(0xB17217F7D1CF79AC));
574 klog2 = floatx80_mul(fp1, logof2, status); /* FP1 IS K*LOG2 */
575 fp2 = floatx80_mul(fp0, fp0, status); /* FP2 IS V=U*U */
580 fp1 = floatx80_mul(fp1, float64_to_floatx80(
581 make_float64(0x3FC2499AB5E4040B), status),
583 fp2 = floatx80_mul(fp2, float64_to_floatx80(
584 make_float64(0xBFC555B5848CB7DB), status),
586 fp1 = floatx80_add(fp1, float64_to_floatx80(
587 make_float64(0x3FC99999987D8730), status),
588 status); /* A4+V*A6 */
589 fp2 = floatx80_add(fp2, float64_to_floatx80(
590 make_float64(0xBFCFFFFFFF6F7E97), status),
591 status); /* A3+V*A5 */
592 fp1 = floatx80_mul(fp1, fp3, status); /* V*(A4+V*A6) */
593 fp2 = floatx80_mul(fp2, fp3, status); /* V*(A3+V*A5) */
594 fp1 = floatx80_add(fp1, float64_to_floatx80(
595 make_float64(0x3FD55555555555A4), status),
596 status); /* A2+V*(A4+V*A6) */
597 fp2 = floatx80_add(fp2, float64_to_floatx80(
598 make_float64(0xBFE0000000000008), status),
599 status); /* A1+V*(A3+V*A5) */
600 fp1 = floatx80_mul(fp1, fp3, status); /* V*(A2+V*(A4+V*A6)) */
601 fp2 = floatx80_mul(fp2, fp3, status); /* V*(A1+V*(A3+V*A5)) */
602 fp1 = floatx80_mul(fp1, fp0, status); /* U*V*(A2+V*(A4+V*A6)) */
603 fp0 = floatx80_add(fp0, fp2, status); /* U+V*(A1+V*(A3+V*A5)) */
605 fp1 = floatx80_add(fp1, log_tbl[j + 1],
606 status); /* LOG(F)+U*V*(A2+V*(A4+V*A6)) */
607 fp0 = floatx80_add(fp0, fp1, status); /* FP0 IS LOG(F) + LOG(1+U) */
609 status->float_rounding_mode = user_rnd_mode;
610 status->floatx80_rounding_precision = user_rnd_prec;
612 a = floatx80_add(fp0, klog2, status);
614 float_raise(float_flag_inexact, status);
617 } else { /* |X-1| >= 1/16 */
620 fp1 = floatx80_sub(fp1, float32_to_floatx80(make_float32(0x3F800000),
621 status), status); /* FP1 IS X-1 */
622 fp0 = floatx80_add(fp0, float32_to_floatx80(make_float32(0x3F800000),
623 status), status); /* FP0 IS X+1 */
624 fp1 = floatx80_add(fp1, fp1, status); /* FP1 IS 2(X-1) */
627 fp1 = floatx80_div(fp1, fp0, status); /* U */
629 fp0 = floatx80_mul(fp1, fp1, status); /* FP0 IS V = U*U */
630 fp1 = floatx80_mul(fp0, fp0, status); /* FP1 IS W = V*V */
632 fp3 = float64_to_floatx80(make_float64(0x3F175496ADD7DAD6),
634 fp2 = float64_to_floatx80(make_float64(0x3F3C71C2FE80C7E0),
636 fp3 = floatx80_mul(fp3, fp1, status); /* W*B5 */
637 fp2 = floatx80_mul(fp2, fp1, status); /* W*B4 */
638 fp3 = floatx80_add(fp3, float64_to_floatx80(
639 make_float64(0x3F624924928BCCFF), status),
640 status); /* B3+W*B5 */
641 fp2 = floatx80_add(fp2, float64_to_floatx80(
642 make_float64(0x3F899999999995EC), status),
643 status); /* B2+W*B4 */
644 fp1 = floatx80_mul(fp1, fp3, status); /* W*(B3+W*B5) */
645 fp2 = floatx80_mul(fp2, fp0, status); /* V*(B2+W*B4) */
646 fp1 = floatx80_add(fp1, float64_to_floatx80(
647 make_float64(0x3FB5555555555555), status),
648 status); /* B1+W*(B3+W*B5) */
650 fp0 = floatx80_mul(fp0, saveu, status); /* FP0 IS U*V */
651 fp1 = floatx80_add(fp1, fp2, status); /* B1+W*(B3+W*B5) + V*(B2+W*B4) */
652 fp0 = floatx80_mul(fp0, fp1,
653 status); /* U*V*([B1+W*(B3+W*B5)] + [V*(B2+W*B4)]) */
655 status->float_rounding_mode = user_rnd_mode;
656 status->floatx80_rounding_precision = user_rnd_prec;
658 a = floatx80_add(fp0, saveu, status);
660 /*if (!floatx80_is_zero(a)) { */
661 float_raise(float_flag_inexact, status);
668 /*----------------------------------------------------------------------------
670 *----------------------------------------------------------------------------*/
672 floatx80 floatx80_log10(floatx80 a, float_status *status)
678 int8_t user_rnd_mode, user_rnd_prec;
682 aSig = extractFloatx80Frac(a);
683 aExp = extractFloatx80Exp(a);
684 aSign = extractFloatx80Sign(a);
686 if (aExp == 0x7FFF) {
687 if ((uint64_t) (aSig << 1)) {
688 propagateFloatx80NaNOneArg(a, status);
691 return packFloatx80(0, floatx80_infinity.high,
692 floatx80_infinity.low);
696 if (aExp == 0 && aSig == 0) {
697 float_raise(float_flag_divbyzero, status);
698 return packFloatx80(1, floatx80_infinity.high,
699 floatx80_infinity.low);
703 float_raise(float_flag_invalid, status);
704 return floatx80_default_nan(status);
707 user_rnd_mode = status->float_rounding_mode;
708 user_rnd_prec = status->floatx80_rounding_precision;
709 status->float_rounding_mode = float_round_nearest_even;
710 status->floatx80_rounding_precision = 80;
712 fp0 = floatx80_logn(a, status);
713 fp1 = packFloatx80(0, 0x3FFD, LIT64(0xDE5BD8A937287195)); /* INV_L10 */
715 status->float_rounding_mode = user_rnd_mode;
716 status->floatx80_rounding_precision = user_rnd_prec;
718 a = floatx80_mul(fp0, fp1, status); /* LOGN(X)*INV_L10 */
720 float_raise(float_flag_inexact, status);
725 /*----------------------------------------------------------------------------
727 *----------------------------------------------------------------------------*/
729 floatx80 floatx80_log2(floatx80 a, float_status *status)
735 int8_t user_rnd_mode, user_rnd_prec;
739 aSig = extractFloatx80Frac(a);
740 aExp = extractFloatx80Exp(a);
741 aSign = extractFloatx80Sign(a);
743 if (aExp == 0x7FFF) {
744 if ((uint64_t) (aSig << 1)) {
745 propagateFloatx80NaNOneArg(a, status);
748 return packFloatx80(0, floatx80_infinity.high,
749 floatx80_infinity.low);
755 float_raise(float_flag_divbyzero, status);
756 return packFloatx80(1, floatx80_infinity.high,
757 floatx80_infinity.low);
759 normalizeFloatx80Subnormal(aSig, &aExp, &aSig);
763 float_raise(float_flag_invalid, status);
764 return floatx80_default_nan(status);
767 user_rnd_mode = status->float_rounding_mode;
768 user_rnd_prec = status->floatx80_rounding_precision;
769 status->float_rounding_mode = float_round_nearest_even;
770 status->floatx80_rounding_precision = 80;
772 if (aSig == one_sig) { /* X is 2^k */
773 status->float_rounding_mode = user_rnd_mode;
774 status->floatx80_rounding_precision = user_rnd_prec;
776 a = int32_to_floatx80(aExp - 0x3FFF, status);
778 fp0 = floatx80_logn(a, status);
779 fp1 = packFloatx80(0, 0x3FFF, LIT64(0xB8AA3B295C17F0BC)); /* INV_L2 */
781 status->float_rounding_mode = user_rnd_mode;
782 status->floatx80_rounding_precision = user_rnd_prec;
784 a = floatx80_mul(fp0, fp1, status); /* LOGN(X)*INV_L2 */
787 float_raise(float_flag_inexact, status);
792 /*----------------------------------------------------------------------------
794 *----------------------------------------------------------------------------*/
796 floatx80 floatx80_etox(floatx80 a, float_status *status)
802 int8_t user_rnd_mode, user_rnd_prec;
804 int32_t compact, n, j, k, m, m1;
805 floatx80 fp0, fp1, fp2, fp3, l2, scale, adjscale;
808 aSig = extractFloatx80Frac(a);
809 aExp = extractFloatx80Exp(a);
810 aSign = extractFloatx80Sign(a);
812 if (aExp == 0x7FFF) {
813 if ((uint64_t) (aSig << 1)) {
814 return propagateFloatx80NaNOneArg(a, status);
817 return packFloatx80(0, 0, 0);
819 return packFloatx80(0, floatx80_infinity.high,
820 floatx80_infinity.low);
823 if (aExp == 0 && aSig == 0) {
824 return packFloatx80(0, one_exp, one_sig);
827 user_rnd_mode = status->float_rounding_mode;
828 user_rnd_prec = status->floatx80_rounding_precision;
829 status->float_rounding_mode = float_round_nearest_even;
830 status->floatx80_rounding_precision = 80;
834 if (aExp >= 0x3FBE) { /* |X| >= 2^(-65) */
835 compact = floatx80_make_compact(aExp, aSig);
837 if (compact < 0x400CB167) { /* |X| < 16380 log2 */
840 fp0 = floatx80_mul(fp0, float32_to_floatx80(
841 make_float32(0x42B8AA3B), status),
842 status); /* 64/log2 * X */
844 n = floatx80_to_int32(fp0, status); /* int(64/log2*X) */
845 fp0 = int32_to_floatx80(n, status);
847 j = n & 0x3F; /* J = N mod 64 */
848 m = n / 64; /* NOTE: this is really arithmetic right shift by 6 */
850 /* arithmetic right shift is division and
851 * round towards minus infinity
855 m += 0x3FFF; /* biased exponent of 2^(M) */
859 fp0 = floatx80_mul(fp0, float32_to_floatx80(
860 make_float32(0xBC317218), status),
861 status); /* N * L1, L1 = lead(-log2/64) */
862 l2 = packFloatx80(0, 0x3FDC, LIT64(0x82E308654361C4C6));
863 fp2 = floatx80_mul(fp2, l2, status); /* N * L2, L1+L2 = -log2/64 */
864 fp0 = floatx80_add(fp0, fp1, status); /* X + N*L1 */
865 fp0 = floatx80_add(fp0, fp2, status); /* R */
867 fp1 = floatx80_mul(fp0, fp0, status); /* S = R*R */
868 fp2 = float32_to_floatx80(make_float32(0x3AB60B70),
870 fp2 = floatx80_mul(fp2, fp1, status); /* fp2 is S*A5 */
871 fp3 = floatx80_mul(float32_to_floatx80(make_float32(0x3C088895),
873 status); /* fp3 is S*A4 */
874 fp2 = floatx80_add(fp2, float64_to_floatx80(make_float64(
875 0x3FA5555555554431), status),
876 status); /* fp2 is A3+S*A5 */
877 fp3 = floatx80_add(fp3, float64_to_floatx80(make_float64(
878 0x3FC5555555554018), status),
879 status); /* fp3 is A2+S*A4 */
880 fp2 = floatx80_mul(fp2, fp1, status); /* fp2 is S*(A3+S*A5) */
881 fp3 = floatx80_mul(fp3, fp1, status); /* fp3 is S*(A2+S*A4) */
882 fp2 = floatx80_add(fp2, float32_to_floatx80(
883 make_float32(0x3F000000), status),
884 status); /* fp2 is A1+S*(A3+S*A5) */
885 fp3 = floatx80_mul(fp3, fp0, status); /* fp3 IS R*S*(A2+S*A4) */
886 fp2 = floatx80_mul(fp2, fp1,
887 status); /* fp2 IS S*(A1+S*(A3+S*A5)) */
888 fp0 = floatx80_add(fp0, fp3, status); /* fp0 IS R+R*S*(A2+S*A4) */
889 fp0 = floatx80_add(fp0, fp2, status); /* fp0 IS EXP(R) - 1 */
892 fp0 = floatx80_mul(fp0, fp1, status); /* 2^(J/64)*(Exp(R)-1) */
893 fp0 = floatx80_add(fp0, float32_to_floatx80(exp_tbl2[j], status),
894 status); /* accurate 2^(J/64) */
895 fp0 = floatx80_add(fp0, fp1,
896 status); /* 2^(J/64) + 2^(J/64)*(Exp(R)-1) */
898 scale = packFloatx80(0, m, one_sig);
900 adjscale = packFloatx80(0, m1, one_sig);
901 fp0 = floatx80_mul(fp0, adjscale, status);
904 status->float_rounding_mode = user_rnd_mode;
905 status->floatx80_rounding_precision = user_rnd_prec;
907 a = floatx80_mul(fp0, scale, status);
909 float_raise(float_flag_inexact, status);
912 } else { /* |X| >= 16380 log2 */
913 if (compact > 0x400CB27C) { /* |X| >= 16480 log2 */
914 status->float_rounding_mode = user_rnd_mode;
915 status->floatx80_rounding_precision = user_rnd_prec;
917 a = roundAndPackFloatx80(
918 status->floatx80_rounding_precision,
919 0, -0x1000, aSig, 0, status);
921 a = roundAndPackFloatx80(
922 status->floatx80_rounding_precision,
923 0, 0x8000, aSig, 0, status);
925 float_raise(float_flag_inexact, status);
931 fp0 = floatx80_mul(fp0, float32_to_floatx80(
932 make_float32(0x42B8AA3B), status),
933 status); /* 64/log2 * X */
935 n = floatx80_to_int32(fp0, status); /* int(64/log2*X) */
936 fp0 = int32_to_floatx80(n, status);
938 j = n & 0x3F; /* J = N mod 64 */
939 /* NOTE: this is really arithmetic right shift by 6 */
942 /* arithmetic right shift is division and
943 * round towards minus infinity
947 /* NOTE: this is really arithmetic right shift by 1 */
949 if (k < 0 && (k & 1)) {
950 /* arithmetic right shift is division and
951 * round towards minus infinity
956 m1 += 0x3FFF; /* biased exponent of 2^(M1) */
957 m += 0x3FFF; /* biased exponent of 2^(M) */
962 } else { /* |X| < 2^(-65) */
963 status->float_rounding_mode = user_rnd_mode;
964 status->floatx80_rounding_precision = user_rnd_prec;
966 a = floatx80_add(a, float32_to_floatx80(make_float32(0x3F800000),
967 status), status); /* 1 + X */
969 float_raise(float_flag_inexact, status);
975 /*----------------------------------------------------------------------------
977 *----------------------------------------------------------------------------*/
979 floatx80 floatx80_twotox(floatx80 a, float_status *status)
985 int8_t user_rnd_mode, user_rnd_prec;
987 int32_t compact, n, j, l, m, m1;
988 floatx80 fp0, fp1, fp2, fp3, adjfact, fact1, fact2;
990 aSig = extractFloatx80Frac(a);
991 aExp = extractFloatx80Exp(a);
992 aSign = extractFloatx80Sign(a);
994 if (aExp == 0x7FFF) {
995 if ((uint64_t) (aSig << 1)) {
996 return propagateFloatx80NaNOneArg(a, status);
999 return packFloatx80(0, 0, 0);
1001 return packFloatx80(0, floatx80_infinity.high,
1002 floatx80_infinity.low);
1005 if (aExp == 0 && aSig == 0) {
1006 return packFloatx80(0, one_exp, one_sig);
1009 user_rnd_mode = status->float_rounding_mode;
1010 user_rnd_prec = status->floatx80_rounding_precision;
1011 status->float_rounding_mode = float_round_nearest_even;
1012 status->floatx80_rounding_precision = 80;
1016 compact = floatx80_make_compact(aExp, aSig);
1018 if (compact < 0x3FB98000 || compact > 0x400D80C0) {
1019 /* |X| > 16480 or |X| < 2^(-70) */
1020 if (compact > 0x3FFF8000) { /* |X| > 16480 */
1021 status->float_rounding_mode = user_rnd_mode;
1022 status->floatx80_rounding_precision = user_rnd_prec;
1025 return roundAndPackFloatx80(status->floatx80_rounding_precision,
1026 0, -0x1000, aSig, 0, status);
1028 return roundAndPackFloatx80(status->floatx80_rounding_precision,
1029 0, 0x8000, aSig, 0, status);
1031 } else { /* |X| < 2^(-70) */
1032 status->float_rounding_mode = user_rnd_mode;
1033 status->floatx80_rounding_precision = user_rnd_prec;
1035 a = floatx80_add(fp0, float32_to_floatx80(
1036 make_float32(0x3F800000), status),
1037 status); /* 1 + X */
1039 float_raise(float_flag_inexact, status);
1043 } else { /* 2^(-70) <= |X| <= 16480 */
1045 fp1 = floatx80_mul(fp1, float32_to_floatx80(
1046 make_float32(0x42800000), status),
1047 status); /* X * 64 */
1048 n = floatx80_to_int32(fp1, status);
1049 fp1 = int32_to_floatx80(n, status);
1051 l = n / 64; /* NOTE: this is really arithmetic right shift by 6 */
1053 /* arithmetic right shift is division and
1054 * round towards minus infinity
1058 m = l / 2; /* NOTE: this is really arithmetic right shift by 1 */
1059 if (l < 0 && (l & 1)) {
1060 /* arithmetic right shift is division and
1061 * round towards minus infinity
1066 m1 += 0x3FFF; /* ADJFACT IS 2^(M') */
1068 adjfact = packFloatx80(0, m1, one_sig);
1069 fact1 = exp2_tbl[j];
1071 fact2.high = exp2_tbl2[j] >> 16;
1073 fact2.low = (uint64_t)(exp2_tbl2[j] & 0xFFFF);
1076 fp1 = floatx80_mul(fp1, float32_to_floatx80(
1077 make_float32(0x3C800000), status),
1078 status); /* (1/64)*N */
1079 fp0 = floatx80_sub(fp0, fp1, status); /* X - (1/64)*INT(64 X) */
1080 fp2 = packFloatx80(0, 0x3FFE, LIT64(0xB17217F7D1CF79AC)); /* LOG2 */
1081 fp0 = floatx80_mul(fp0, fp2, status); /* R */
1084 fp1 = floatx80_mul(fp0, fp0, status); /* S = R*R */
1085 fp2 = float64_to_floatx80(make_float64(0x3F56C16D6F7BD0B2),
1087 fp3 = float64_to_floatx80(make_float64(0x3F811112302C712C),
1089 fp2 = floatx80_mul(fp2, fp1, status); /* S*A5 */
1090 fp3 = floatx80_mul(fp3, fp1, status); /* S*A4 */
1091 fp2 = floatx80_add(fp2, float64_to_floatx80(
1092 make_float64(0x3FA5555555554CC1), status),
1093 status); /* A3+S*A5 */
1094 fp3 = floatx80_add(fp3, float64_to_floatx80(
1095 make_float64(0x3FC5555555554A54), status),
1096 status); /* A2+S*A4 */
1097 fp2 = floatx80_mul(fp2, fp1, status); /* S*(A3+S*A5) */
1098 fp3 = floatx80_mul(fp3, fp1, status); /* S*(A2+S*A4) */
1099 fp2 = floatx80_add(fp2, float64_to_floatx80(
1100 make_float64(0x3FE0000000000000), status),
1101 status); /* A1+S*(A3+S*A5) */
1102 fp3 = floatx80_mul(fp3, fp0, status); /* R*S*(A2+S*A4) */
1104 fp2 = floatx80_mul(fp2, fp1, status); /* S*(A1+S*(A3+S*A5)) */
1105 fp0 = floatx80_add(fp0, fp3, status); /* R+R*S*(A2+S*A4) */
1106 fp0 = floatx80_add(fp0, fp2, status); /* EXP(R) - 1 */
1108 fp0 = floatx80_mul(fp0, fact1, status);
1109 fp0 = floatx80_add(fp0, fact2, status);
1110 fp0 = floatx80_add(fp0, fact1, status);
1112 status->float_rounding_mode = user_rnd_mode;
1113 status->floatx80_rounding_precision = user_rnd_prec;
1115 a = floatx80_mul(fp0, adjfact, status);
1117 float_raise(float_flag_inexact, status);
1123 /*----------------------------------------------------------------------------
1125 *----------------------------------------------------------------------------*/
1127 floatx80 floatx80_tentox(floatx80 a, float_status *status)
1133 int8_t user_rnd_mode, user_rnd_prec;
1135 int32_t compact, n, j, l, m, m1;
1136 floatx80 fp0, fp1, fp2, fp3, adjfact, fact1, fact2;
1138 aSig = extractFloatx80Frac(a);
1139 aExp = extractFloatx80Exp(a);
1140 aSign = extractFloatx80Sign(a);
1142 if (aExp == 0x7FFF) {
1143 if ((uint64_t) (aSig << 1)) {
1144 return propagateFloatx80NaNOneArg(a, status);
1147 return packFloatx80(0, 0, 0);
1149 return packFloatx80(0, floatx80_infinity.high,
1150 floatx80_infinity.low);
1153 if (aExp == 0 && aSig == 0) {
1154 return packFloatx80(0, one_exp, one_sig);
1157 user_rnd_mode = status->float_rounding_mode;
1158 user_rnd_prec = status->floatx80_rounding_precision;
1159 status->float_rounding_mode = float_round_nearest_even;
1160 status->floatx80_rounding_precision = 80;
1164 compact = floatx80_make_compact(aExp, aSig);
1166 if (compact < 0x3FB98000 || compact > 0x400B9B07) {
1167 /* |X| > 16480 LOG2/LOG10 or |X| < 2^(-70) */
1168 if (compact > 0x3FFF8000) { /* |X| > 16480 */
1169 status->float_rounding_mode = user_rnd_mode;
1170 status->floatx80_rounding_precision = user_rnd_prec;
1173 return roundAndPackFloatx80(status->floatx80_rounding_precision,
1174 0, -0x1000, aSig, 0, status);
1176 return roundAndPackFloatx80(status->floatx80_rounding_precision,
1177 0, 0x8000, aSig, 0, status);
1179 } else { /* |X| < 2^(-70) */
1180 status->float_rounding_mode = user_rnd_mode;
1181 status->floatx80_rounding_precision = user_rnd_prec;
1183 a = floatx80_add(fp0, float32_to_floatx80(
1184 make_float32(0x3F800000), status),
1185 status); /* 1 + X */
1187 float_raise(float_flag_inexact, status);
1191 } else { /* 2^(-70) <= |X| <= 16480 LOG 2 / LOG 10 */
1193 fp1 = floatx80_mul(fp1, float64_to_floatx80(
1194 make_float64(0x406A934F0979A371),
1195 status), status); /* X*64*LOG10/LOG2 */
1196 n = floatx80_to_int32(fp1, status); /* N=INT(X*64*LOG10/LOG2) */
1197 fp1 = int32_to_floatx80(n, status);
1200 l = n / 64; /* NOTE: this is really arithmetic right shift by 6 */
1202 /* arithmetic right shift is division and
1203 * round towards minus infinity
1207 m = l / 2; /* NOTE: this is really arithmetic right shift by 1 */
1208 if (l < 0 && (l & 1)) {
1209 /* arithmetic right shift is division and
1210 * round towards minus infinity
1215 m1 += 0x3FFF; /* ADJFACT IS 2^(M') */
1217 adjfact = packFloatx80(0, m1, one_sig);
1218 fact1 = exp2_tbl[j];
1220 fact2.high = exp2_tbl2[j] >> 16;
1222 fact2.low = (uint64_t)(exp2_tbl2[j] & 0xFFFF);
1226 fp1 = floatx80_mul(fp1, float64_to_floatx80(
1227 make_float64(0x3F734413509F8000), status),
1228 status); /* N*(LOG2/64LOG10)_LEAD */
1229 fp3 = packFloatx80(1, 0x3FCD, LIT64(0xC0219DC1DA994FD2));
1230 fp2 = floatx80_mul(fp2, fp3, status); /* N*(LOG2/64LOG10)_TRAIL */
1231 fp0 = floatx80_sub(fp0, fp1, status); /* X - N L_LEAD */
1232 fp0 = floatx80_sub(fp0, fp2, status); /* X - N L_TRAIL */
1233 fp2 = packFloatx80(0, 0x4000, LIT64(0x935D8DDDAAA8AC17)); /* LOG10 */
1234 fp0 = floatx80_mul(fp0, fp2, status); /* R */
1237 fp1 = floatx80_mul(fp0, fp0, status); /* S = R*R */
1238 fp2 = float64_to_floatx80(make_float64(0x3F56C16D6F7BD0B2),
1240 fp3 = float64_to_floatx80(make_float64(0x3F811112302C712C),
1242 fp2 = floatx80_mul(fp2, fp1, status); /* S*A5 */
1243 fp3 = floatx80_mul(fp3, fp1, status); /* S*A4 */
1244 fp2 = floatx80_add(fp2, float64_to_floatx80(
1245 make_float64(0x3FA5555555554CC1), status),
1246 status); /* A3+S*A5 */
1247 fp3 = floatx80_add(fp3, float64_to_floatx80(
1248 make_float64(0x3FC5555555554A54), status),
1249 status); /* A2+S*A4 */
1250 fp2 = floatx80_mul(fp2, fp1, status); /* S*(A3+S*A5) */
1251 fp3 = floatx80_mul(fp3, fp1, status); /* S*(A2+S*A4) */
1252 fp2 = floatx80_add(fp2, float64_to_floatx80(
1253 make_float64(0x3FE0000000000000), status),
1254 status); /* A1+S*(A3+S*A5) */
1255 fp3 = floatx80_mul(fp3, fp0, status); /* R*S*(A2+S*A4) */
1257 fp2 = floatx80_mul(fp2, fp1, status); /* S*(A1+S*(A3+S*A5)) */
1258 fp0 = floatx80_add(fp0, fp3, status); /* R+R*S*(A2+S*A4) */
1259 fp0 = floatx80_add(fp0, fp2, status); /* EXP(R) - 1 */
1261 fp0 = floatx80_mul(fp0, fact1, status);
1262 fp0 = floatx80_add(fp0, fact2, status);
1263 fp0 = floatx80_add(fp0, fact1, status);
1265 status->float_rounding_mode = user_rnd_mode;
1266 status->floatx80_rounding_precision = user_rnd_prec;
1268 a = floatx80_mul(fp0, adjfact, status);
1270 float_raise(float_flag_inexact, status);
1276 /*----------------------------------------------------------------------------
1278 *----------------------------------------------------------------------------*/
1280 floatx80 floatx80_tan(floatx80 a, float_status *status)
1284 uint64_t aSig, xSig;
1286 int8_t user_rnd_mode, user_rnd_prec;
1288 int32_t compact, l, n, j;
1289 floatx80 fp0, fp1, fp2, fp3, fp4, fp5, invtwopi, twopi1, twopi2;
1293 aSig = extractFloatx80Frac(a);
1294 aExp = extractFloatx80Exp(a);
1295 aSign = extractFloatx80Sign(a);
1297 if (aExp == 0x7FFF) {
1298 if ((uint64_t) (aSig << 1)) {
1299 return propagateFloatx80NaNOneArg(a, status);
1301 float_raise(float_flag_invalid, status);
1302 return floatx80_default_nan(status);
1305 if (aExp == 0 && aSig == 0) {
1306 return packFloatx80(aSign, 0, 0);
1309 user_rnd_mode = status->float_rounding_mode;
1310 user_rnd_prec = status->floatx80_rounding_precision;
1311 status->float_rounding_mode = float_round_nearest_even;
1312 status->floatx80_rounding_precision = 80;
1314 compact = floatx80_make_compact(aExp, aSig);
1318 if (compact < 0x3FD78000 || compact > 0x4004BC7E) {
1319 /* 2^(-40) > |X| > 15 PI */
1320 if (compact > 0x3FFF8000) { /* |X| >= 15 PI */
1322 fp1 = packFloatx80(0, 0, 0);
1323 if (compact == 0x7FFEFFFF) {
1324 twopi1 = packFloatx80(aSign ^ 1, 0x7FFE,
1325 LIT64(0xC90FDAA200000000));
1326 twopi2 = packFloatx80(aSign ^ 1, 0x7FDC,
1327 LIT64(0x85A308D300000000));
1328 fp0 = floatx80_add(fp0, twopi1, status);
1330 fp0 = floatx80_add(fp0, twopi2, status);
1331 fp1 = floatx80_sub(fp1, fp0, status);
1332 fp1 = floatx80_add(fp1, twopi2, status);
1335 xSign = extractFloatx80Sign(fp0);
1336 xExp = extractFloatx80Exp(fp0);
1345 invtwopi = packFloatx80(0, 0x3FFE - l,
1346 LIT64(0xA2F9836E4E44152A)); /* INVTWOPI */
1347 twopi1 = packFloatx80(0, 0x3FFF + l, LIT64(0xC90FDAA200000000));
1348 twopi2 = packFloatx80(0, 0x3FDD + l, LIT64(0x85A308D300000000));
1350 /* SIGN(INARG)*2^63 IN SGL */
1351 twoto63 = packFloat32(xSign, 0xBE, 0);
1353 fp2 = floatx80_mul(fp0, invtwopi, status);
1354 fp2 = floatx80_add(fp2, float32_to_floatx80(twoto63, status),
1355 status); /* THE FRACT PART OF FP2 IS ROUNDED */
1356 fp2 = floatx80_sub(fp2, float32_to_floatx80(twoto63, status),
1357 status); /* FP2 is N */
1358 fp4 = floatx80_mul(twopi1, fp2, status); /* W = N*P1 */
1359 fp5 = floatx80_mul(twopi2, fp2, status); /* w = N*P2 */
1360 fp3 = floatx80_add(fp4, fp5, status); /* FP3 is P */
1361 fp4 = floatx80_sub(fp4, fp3, status); /* W-P */
1362 fp0 = floatx80_sub(fp0, fp3, status); /* FP0 is A := R - P */
1363 fp4 = floatx80_add(fp4, fp5, status); /* FP4 is p = (W-P)+w */
1364 fp3 = fp0; /* FP3 is A */
1365 fp1 = floatx80_sub(fp1, fp4, status); /* FP1 is a := r - p */
1366 fp0 = floatx80_add(fp0, fp1, status); /* FP0 is R := A+a */
1369 n = floatx80_to_int32(fp2, status);
1372 fp3 = floatx80_sub(fp3, fp0, status); /* A-R */
1373 fp1 = floatx80_add(fp1, fp3, status); /* FP1 is r := (A-R)+a */
1376 status->float_rounding_mode = user_rnd_mode;
1377 status->floatx80_rounding_precision = user_rnd_prec;
1379 a = floatx80_move(a, status);
1381 float_raise(float_flag_inexact, status);
1386 fp1 = floatx80_mul(fp0, float64_to_floatx80(
1387 make_float64(0x3FE45F306DC9C883), status),
1388 status); /* X*2/PI */
1390 n = floatx80_to_int32(fp1, status);
1393 fp0 = floatx80_sub(fp0, pi_tbl[j], status); /* X-Y1 */
1394 fp0 = floatx80_sub(fp0, float32_to_floatx80(pi_tbl2[j], status),
1395 status); /* FP0 IS R = (X-Y1)-Y2 */
1401 fp0 = floatx80_mul(fp0, fp0, status); /* S = R*R */
1402 fp3 = float64_to_floatx80(make_float64(0x3EA0B759F50F8688),
1404 fp2 = float64_to_floatx80(make_float64(0xBEF2BAA5A8924F04),
1406 fp3 = floatx80_mul(fp3, fp0, status); /* SQ4 */
1407 fp2 = floatx80_mul(fp2, fp0, status); /* SP3 */
1408 fp3 = floatx80_add(fp3, float64_to_floatx80(
1409 make_float64(0xBF346F59B39BA65F), status),
1410 status); /* Q3+SQ4 */
1411 fp4 = packFloatx80(0, 0x3FF6, LIT64(0xE073D3FC199C4A00));
1412 fp2 = floatx80_add(fp2, fp4, status); /* P2+SP3 */
1413 fp3 = floatx80_mul(fp3, fp0, status); /* S(Q3+SQ4) */
1414 fp2 = floatx80_mul(fp2, fp0, status); /* S(P2+SP3) */
1415 fp4 = packFloatx80(0, 0x3FF9, LIT64(0xD23CD68415D95FA1));
1416 fp3 = floatx80_add(fp3, fp4, status); /* Q2+S(Q3+SQ4) */
1417 fp4 = packFloatx80(1, 0x3FFC, LIT64(0x8895A6C5FB423BCA));
1418 fp2 = floatx80_add(fp2, fp4, status); /* P1+S(P2+SP3) */
1419 fp3 = floatx80_mul(fp3, fp0, status); /* S(Q2+S(Q3+SQ4)) */
1420 fp2 = floatx80_mul(fp2, fp0, status); /* S(P1+S(P2+SP3)) */
1421 fp4 = packFloatx80(1, 0x3FFD, LIT64(0xEEF57E0DA84BC8CE));
1422 fp3 = floatx80_add(fp3, fp4, status); /* Q1+S(Q2+S(Q3+SQ4)) */
1423 fp2 = floatx80_mul(fp2, fp1, status); /* RS(P1+S(P2+SP3)) */
1424 fp0 = floatx80_mul(fp0, fp3, status); /* S(Q1+S(Q2+S(Q3+SQ4))) */
1425 fp1 = floatx80_add(fp1, fp2, status); /* R+RS(P1+S(P2+SP3)) */
1426 fp0 = floatx80_add(fp0, float32_to_floatx80(
1427 make_float32(0x3F800000), status),
1428 status); /* 1+S(Q1+S(Q2+S(Q3+SQ4))) */
1430 xSign = extractFloatx80Sign(fp1);
1431 xExp = extractFloatx80Exp(fp1);
1432 xSig = extractFloatx80Frac(fp1);
1434 fp1 = packFloatx80(xSign, xExp, xSig);
1436 status->float_rounding_mode = user_rnd_mode;
1437 status->floatx80_rounding_precision = user_rnd_prec;
1439 a = floatx80_div(fp0, fp1, status);
1441 float_raise(float_flag_inexact, status);
1445 fp1 = floatx80_mul(fp0, fp0, status); /* S = R*R */
1446 fp3 = float64_to_floatx80(make_float64(0x3EA0B759F50F8688),
1448 fp2 = float64_to_floatx80(make_float64(0xBEF2BAA5A8924F04),
1450 fp3 = floatx80_mul(fp3, fp1, status); /* SQ4 */
1451 fp2 = floatx80_mul(fp2, fp1, status); /* SP3 */
1452 fp3 = floatx80_add(fp3, float64_to_floatx80(
1453 make_float64(0xBF346F59B39BA65F), status),
1454 status); /* Q3+SQ4 */
1455 fp4 = packFloatx80(0, 0x3FF6, LIT64(0xE073D3FC199C4A00));
1456 fp2 = floatx80_add(fp2, fp4, status); /* P2+SP3 */
1457 fp3 = floatx80_mul(fp3, fp1, status); /* S(Q3+SQ4) */
1458 fp2 = floatx80_mul(fp2, fp1, status); /* S(P2+SP3) */
1459 fp4 = packFloatx80(0, 0x3FF9, LIT64(0xD23CD68415D95FA1));
1460 fp3 = floatx80_add(fp3, fp4, status); /* Q2+S(Q3+SQ4) */
1461 fp4 = packFloatx80(1, 0x3FFC, LIT64(0x8895A6C5FB423BCA));
1462 fp2 = floatx80_add(fp2, fp4, status); /* P1+S(P2+SP3) */
1463 fp3 = floatx80_mul(fp3, fp1, status); /* S(Q2+S(Q3+SQ4)) */
1464 fp2 = floatx80_mul(fp2, fp1, status); /* S(P1+S(P2+SP3)) */
1465 fp4 = packFloatx80(1, 0x3FFD, LIT64(0xEEF57E0DA84BC8CE));
1466 fp3 = floatx80_add(fp3, fp4, status); /* Q1+S(Q2+S(Q3+SQ4)) */
1467 fp2 = floatx80_mul(fp2, fp0, status); /* RS(P1+S(P2+SP3)) */
1468 fp1 = floatx80_mul(fp1, fp3, status); /* S(Q1+S(Q2+S(Q3+SQ4))) */
1469 fp0 = floatx80_add(fp0, fp2, status); /* R+RS(P1+S(P2+SP3)) */
1470 fp1 = floatx80_add(fp1, float32_to_floatx80(
1471 make_float32(0x3F800000), status),
1472 status); /* 1+S(Q1+S(Q2+S(Q3+SQ4))) */
1474 status->float_rounding_mode = user_rnd_mode;
1475 status->floatx80_rounding_precision = user_rnd_prec;
1477 a = floatx80_div(fp0, fp1, status);
1479 float_raise(float_flag_inexact, status);
1486 /*----------------------------------------------------------------------------
1488 *----------------------------------------------------------------------------*/
1490 floatx80 floatx80_sin(floatx80 a, float_status *status)
1494 uint64_t aSig, xSig;
1496 int8_t user_rnd_mode, user_rnd_prec;
1498 int32_t compact, l, n, j;
1499 floatx80 fp0, fp1, fp2, fp3, fp4, fp5, x, invtwopi, twopi1, twopi2;
1500 float32 posneg1, twoto63;
1503 aSig = extractFloatx80Frac(a);
1504 aExp = extractFloatx80Exp(a);
1505 aSign = extractFloatx80Sign(a);
1507 if (aExp == 0x7FFF) {
1508 if ((uint64_t) (aSig << 1)) {
1509 return propagateFloatx80NaNOneArg(a, status);
1511 float_raise(float_flag_invalid, status);
1512 return floatx80_default_nan(status);
1515 if (aExp == 0 && aSig == 0) {
1516 return packFloatx80(aSign, 0, 0);
1519 user_rnd_mode = status->float_rounding_mode;
1520 user_rnd_prec = status->floatx80_rounding_precision;
1521 status->float_rounding_mode = float_round_nearest_even;
1522 status->floatx80_rounding_precision = 80;
1524 compact = floatx80_make_compact(aExp, aSig);
1528 if (compact < 0x3FD78000 || compact > 0x4004BC7E) {
1529 /* 2^(-40) > |X| > 15 PI */
1530 if (compact > 0x3FFF8000) { /* |X| >= 15 PI */
1532 fp1 = packFloatx80(0, 0, 0);
1533 if (compact == 0x7FFEFFFF) {
1534 twopi1 = packFloatx80(aSign ^ 1, 0x7FFE,
1535 LIT64(0xC90FDAA200000000));
1536 twopi2 = packFloatx80(aSign ^ 1, 0x7FDC,
1537 LIT64(0x85A308D300000000));
1538 fp0 = floatx80_add(fp0, twopi1, status);
1540 fp0 = floatx80_add(fp0, twopi2, status);
1541 fp1 = floatx80_sub(fp1, fp0, status);
1542 fp1 = floatx80_add(fp1, twopi2, status);
1545 xSign = extractFloatx80Sign(fp0);
1546 xExp = extractFloatx80Exp(fp0);
1555 invtwopi = packFloatx80(0, 0x3FFE - l,
1556 LIT64(0xA2F9836E4E44152A)); /* INVTWOPI */
1557 twopi1 = packFloatx80(0, 0x3FFF + l, LIT64(0xC90FDAA200000000));
1558 twopi2 = packFloatx80(0, 0x3FDD + l, LIT64(0x85A308D300000000));
1560 /* SIGN(INARG)*2^63 IN SGL */
1561 twoto63 = packFloat32(xSign, 0xBE, 0);
1563 fp2 = floatx80_mul(fp0, invtwopi, status);
1564 fp2 = floatx80_add(fp2, float32_to_floatx80(twoto63, status),
1565 status); /* THE FRACT PART OF FP2 IS ROUNDED */
1566 fp2 = floatx80_sub(fp2, float32_to_floatx80(twoto63, status),
1567 status); /* FP2 is N */
1568 fp4 = floatx80_mul(twopi1, fp2, status); /* W = N*P1 */
1569 fp5 = floatx80_mul(twopi2, fp2, status); /* w = N*P2 */
1570 fp3 = floatx80_add(fp4, fp5, status); /* FP3 is P */
1571 fp4 = floatx80_sub(fp4, fp3, status); /* W-P */
1572 fp0 = floatx80_sub(fp0, fp3, status); /* FP0 is A := R - P */
1573 fp4 = floatx80_add(fp4, fp5, status); /* FP4 is p = (W-P)+w */
1574 fp3 = fp0; /* FP3 is A */
1575 fp1 = floatx80_sub(fp1, fp4, status); /* FP1 is a := r - p */
1576 fp0 = floatx80_add(fp0, fp1, status); /* FP0 is R := A+a */
1579 n = floatx80_to_int32(fp2, status);
1582 fp3 = floatx80_sub(fp3, fp0, status); /* A-R */
1583 fp1 = floatx80_add(fp1, fp3, status); /* FP1 is r := (A-R)+a */
1587 fp0 = float32_to_floatx80(make_float32(0x3F800000),
1590 status->float_rounding_mode = user_rnd_mode;
1591 status->floatx80_rounding_precision = user_rnd_prec;
1594 a = floatx80_move(a, status);
1595 float_raise(float_flag_inexact, status);
1600 fp1 = floatx80_mul(fp0, float64_to_floatx80(
1601 make_float64(0x3FE45F306DC9C883), status),
1602 status); /* X*2/PI */
1604 n = floatx80_to_int32(fp1, status);
1607 fp0 = floatx80_sub(fp0, pi_tbl[j], status); /* X-Y1 */
1608 fp0 = floatx80_sub(fp0, float32_to_floatx80(pi_tbl2[j], status),
1609 status); /* FP0 IS R = (X-Y1)-Y2 */
1614 fp0 = floatx80_mul(fp0, fp0, status); /* FP0 IS S */
1615 fp1 = floatx80_mul(fp0, fp0, status); /* FP1 IS T */
1616 fp2 = float64_to_floatx80(make_float64(0x3D2AC4D0D6011EE3),
1618 fp3 = float64_to_floatx80(make_float64(0xBDA9396F9F45AC19),
1621 xSign = extractFloatx80Sign(fp0); /* X IS S */
1622 xExp = extractFloatx80Exp(fp0);
1623 xSig = extractFloatx80Frac(fp0);
1627 posneg1 = make_float32(0xBF800000); /* -1 */
1630 posneg1 = make_float32(0x3F800000); /* 1 */
1631 } /* X IS NOW R'= SGN*R */
1633 fp2 = floatx80_mul(fp2, fp1, status); /* TB8 */
1634 fp3 = floatx80_mul(fp3, fp1, status); /* TB7 */
1635 fp2 = floatx80_add(fp2, float64_to_floatx80(
1636 make_float64(0x3E21EED90612C972), status),
1637 status); /* B6+TB8 */
1638 fp3 = floatx80_add(fp3, float64_to_floatx80(
1639 make_float64(0xBE927E4FB79D9FCF), status),
1640 status); /* B5+TB7 */
1641 fp2 = floatx80_mul(fp2, fp1, status); /* T(B6+TB8) */
1642 fp3 = floatx80_mul(fp3, fp1, status); /* T(B5+TB7) */
1643 fp2 = floatx80_add(fp2, float64_to_floatx80(
1644 make_float64(0x3EFA01A01A01D423), status),
1645 status); /* B4+T(B6+TB8) */
1646 fp4 = packFloatx80(1, 0x3FF5, LIT64(0xB60B60B60B61D438));
1647 fp3 = floatx80_add(fp3, fp4, status); /* B3+T(B5+TB7) */
1648 fp2 = floatx80_mul(fp2, fp1, status); /* T(B4+T(B6+TB8)) */
1649 fp1 = floatx80_mul(fp1, fp3, status); /* T(B3+T(B5+TB7)) */
1650 fp4 = packFloatx80(0, 0x3FFA, LIT64(0xAAAAAAAAAAAAAB5E));
1651 fp2 = floatx80_add(fp2, fp4, status); /* B2+T(B4+T(B6+TB8)) */
1652 fp1 = floatx80_add(fp1, float32_to_floatx80(
1653 make_float32(0xBF000000), status),
1654 status); /* B1+T(B3+T(B5+TB7)) */
1655 fp0 = floatx80_mul(fp0, fp2, status); /* S(B2+T(B4+T(B6+TB8))) */
1656 fp0 = floatx80_add(fp0, fp1, status); /* [B1+T(B3+T(B5+TB7))]+
1657 * [S(B2+T(B4+T(B6+TB8)))]
1660 x = packFloatx80(xSign, xExp, xSig);
1661 fp0 = floatx80_mul(fp0, x, status);
1663 status->float_rounding_mode = user_rnd_mode;
1664 status->floatx80_rounding_precision = user_rnd_prec;
1666 a = floatx80_add(fp0, float32_to_floatx80(posneg1, status), status);
1668 float_raise(float_flag_inexact, status);
1673 xSign = extractFloatx80Sign(fp0); /* X IS R */
1674 xExp = extractFloatx80Exp(fp0);
1675 xSig = extractFloatx80Frac(fp0);
1677 xSign ^= (n >> 1) & 1; /* X IS NOW R'= SGN*R */
1679 fp0 = floatx80_mul(fp0, fp0, status); /* FP0 IS S */
1680 fp1 = floatx80_mul(fp0, fp0, status); /* FP1 IS T */
1681 fp3 = float64_to_floatx80(make_float64(0xBD6AAA77CCC994F5),
1683 fp2 = float64_to_floatx80(make_float64(0x3DE612097AAE8DA1),
1685 fp3 = floatx80_mul(fp3, fp1, status); /* T*A7 */
1686 fp2 = floatx80_mul(fp2, fp1, status); /* T*A6 */
1687 fp3 = floatx80_add(fp3, float64_to_floatx80(
1688 make_float64(0xBE5AE6452A118AE4), status),
1689 status); /* A5+T*A7 */
1690 fp2 = floatx80_add(fp2, float64_to_floatx80(
1691 make_float64(0x3EC71DE3A5341531), status),
1692 status); /* A4+T*A6 */
1693 fp3 = floatx80_mul(fp3, fp1, status); /* T(A5+TA7) */
1694 fp2 = floatx80_mul(fp2, fp1, status); /* T(A4+TA6) */
1695 fp3 = floatx80_add(fp3, float64_to_floatx80(
1696 make_float64(0xBF2A01A01A018B59), status),
1697 status); /* A3+T(A5+TA7) */
1698 fp4 = packFloatx80(0, 0x3FF8, LIT64(0x88888888888859AF));
1699 fp2 = floatx80_add(fp2, fp4, status); /* A2+T(A4+TA6) */
1700 fp1 = floatx80_mul(fp1, fp3, status); /* T(A3+T(A5+TA7)) */
1701 fp2 = floatx80_mul(fp2, fp0, status); /* S(A2+T(A4+TA6)) */
1702 fp4 = packFloatx80(1, 0x3FFC, LIT64(0xAAAAAAAAAAAAAA99));
1703 fp1 = floatx80_add(fp1, fp4, status); /* A1+T(A3+T(A5+TA7)) */
1704 fp1 = floatx80_add(fp1, fp2,
1705 status); /* [A1+T(A3+T(A5+TA7))]+
1709 x = packFloatx80(xSign, xExp, xSig);
1710 fp0 = floatx80_mul(fp0, x, status); /* R'*S */
1711 fp0 = floatx80_mul(fp0, fp1, status); /* SIN(R')-R' */
1713 status->float_rounding_mode = user_rnd_mode;
1714 status->floatx80_rounding_precision = user_rnd_prec;
1716 a = floatx80_add(fp0, x, status);
1718 float_raise(float_flag_inexact, status);
1725 /*----------------------------------------------------------------------------
1727 *----------------------------------------------------------------------------*/
1729 floatx80 floatx80_cos(floatx80 a, float_status *status)
1733 uint64_t aSig, xSig;
1735 int8_t user_rnd_mode, user_rnd_prec;
1737 int32_t compact, l, n, j;
1738 floatx80 fp0, fp1, fp2, fp3, fp4, fp5, x, invtwopi, twopi1, twopi2;
1739 float32 posneg1, twoto63;
1742 aSig = extractFloatx80Frac(a);
1743 aExp = extractFloatx80Exp(a);
1744 aSign = extractFloatx80Sign(a);
1746 if (aExp == 0x7FFF) {
1747 if ((uint64_t) (aSig << 1)) {
1748 return propagateFloatx80NaNOneArg(a, status);
1750 float_raise(float_flag_invalid, status);
1751 return floatx80_default_nan(status);
1754 if (aExp == 0 && aSig == 0) {
1755 return packFloatx80(0, one_exp, one_sig);
1758 user_rnd_mode = status->float_rounding_mode;
1759 user_rnd_prec = status->floatx80_rounding_precision;
1760 status->float_rounding_mode = float_round_nearest_even;
1761 status->floatx80_rounding_precision = 80;
1763 compact = floatx80_make_compact(aExp, aSig);
1767 if (compact < 0x3FD78000 || compact > 0x4004BC7E) {
1768 /* 2^(-40) > |X| > 15 PI */
1769 if (compact > 0x3FFF8000) { /* |X| >= 15 PI */
1771 fp1 = packFloatx80(0, 0, 0);
1772 if (compact == 0x7FFEFFFF) {
1773 twopi1 = packFloatx80(aSign ^ 1, 0x7FFE,
1774 LIT64(0xC90FDAA200000000));
1775 twopi2 = packFloatx80(aSign ^ 1, 0x7FDC,
1776 LIT64(0x85A308D300000000));
1777 fp0 = floatx80_add(fp0, twopi1, status);
1779 fp0 = floatx80_add(fp0, twopi2, status);
1780 fp1 = floatx80_sub(fp1, fp0, status);
1781 fp1 = floatx80_add(fp1, twopi2, status);
1784 xSign = extractFloatx80Sign(fp0);
1785 xExp = extractFloatx80Exp(fp0);
1794 invtwopi = packFloatx80(0, 0x3FFE - l,
1795 LIT64(0xA2F9836E4E44152A)); /* INVTWOPI */
1796 twopi1 = packFloatx80(0, 0x3FFF + l, LIT64(0xC90FDAA200000000));
1797 twopi2 = packFloatx80(0, 0x3FDD + l, LIT64(0x85A308D300000000));
1799 /* SIGN(INARG)*2^63 IN SGL */
1800 twoto63 = packFloat32(xSign, 0xBE, 0);
1802 fp2 = floatx80_mul(fp0, invtwopi, status);
1803 fp2 = floatx80_add(fp2, float32_to_floatx80(twoto63, status),
1804 status); /* THE FRACT PART OF FP2 IS ROUNDED */
1805 fp2 = floatx80_sub(fp2, float32_to_floatx80(twoto63, status),
1806 status); /* FP2 is N */
1807 fp4 = floatx80_mul(twopi1, fp2, status); /* W = N*P1 */
1808 fp5 = floatx80_mul(twopi2, fp2, status); /* w = N*P2 */
1809 fp3 = floatx80_add(fp4, fp5, status); /* FP3 is P */
1810 fp4 = floatx80_sub(fp4, fp3, status); /* W-P */
1811 fp0 = floatx80_sub(fp0, fp3, status); /* FP0 is A := R - P */
1812 fp4 = floatx80_add(fp4, fp5, status); /* FP4 is p = (W-P)+w */
1813 fp3 = fp0; /* FP3 is A */
1814 fp1 = floatx80_sub(fp1, fp4, status); /* FP1 is a := r - p */
1815 fp0 = floatx80_add(fp0, fp1, status); /* FP0 is R := A+a */
1818 n = floatx80_to_int32(fp2, status);
1821 fp3 = floatx80_sub(fp3, fp0, status); /* A-R */
1822 fp1 = floatx80_add(fp1, fp3, status); /* FP1 is r := (A-R)+a */
1826 fp0 = float32_to_floatx80(make_float32(0x3F800000), status); /* 1 */
1828 status->float_rounding_mode = user_rnd_mode;
1829 status->floatx80_rounding_precision = user_rnd_prec;
1832 a = floatx80_sub(fp0, float32_to_floatx80(
1833 make_float32(0x00800000), status),
1835 float_raise(float_flag_inexact, status);
1840 fp1 = floatx80_mul(fp0, float64_to_floatx80(
1841 make_float64(0x3FE45F306DC9C883), status),
1842 status); /* X*2/PI */
1844 n = floatx80_to_int32(fp1, status);
1847 fp0 = floatx80_sub(fp0, pi_tbl[j], status); /* X-Y1 */
1848 fp0 = floatx80_sub(fp0, float32_to_floatx80(pi_tbl2[j], status),
1849 status); /* FP0 IS R = (X-Y1)-Y2 */
1854 fp0 = floatx80_mul(fp0, fp0, status); /* FP0 IS S */
1855 fp1 = floatx80_mul(fp0, fp0, status); /* FP1 IS T */
1856 fp2 = float64_to_floatx80(make_float64(0x3D2AC4D0D6011EE3),
1858 fp3 = float64_to_floatx80(make_float64(0xBDA9396F9F45AC19),
1861 xSign = extractFloatx80Sign(fp0); /* X IS S */
1862 xExp = extractFloatx80Exp(fp0);
1863 xSig = extractFloatx80Frac(fp0);
1865 if (((n + 1) >> 1) & 1) {
1867 posneg1 = make_float32(0xBF800000); /* -1 */
1870 posneg1 = make_float32(0x3F800000); /* 1 */
1871 } /* X IS NOW R'= SGN*R */
1873 fp2 = floatx80_mul(fp2, fp1, status); /* TB8 */
1874 fp3 = floatx80_mul(fp3, fp1, status); /* TB7 */
1875 fp2 = floatx80_add(fp2, float64_to_floatx80(
1876 make_float64(0x3E21EED90612C972), status),
1877 status); /* B6+TB8 */
1878 fp3 = floatx80_add(fp3, float64_to_floatx80(
1879 make_float64(0xBE927E4FB79D9FCF), status),
1880 status); /* B5+TB7 */
1881 fp2 = floatx80_mul(fp2, fp1, status); /* T(B6+TB8) */
1882 fp3 = floatx80_mul(fp3, fp1, status); /* T(B5+TB7) */
1883 fp2 = floatx80_add(fp2, float64_to_floatx80(
1884 make_float64(0x3EFA01A01A01D423), status),
1885 status); /* B4+T(B6+TB8) */
1886 fp4 = packFloatx80(1, 0x3FF5, LIT64(0xB60B60B60B61D438));
1887 fp3 = floatx80_add(fp3, fp4, status); /* B3+T(B5+TB7) */
1888 fp2 = floatx80_mul(fp2, fp1, status); /* T(B4+T(B6+TB8)) */
1889 fp1 = floatx80_mul(fp1, fp3, status); /* T(B3+T(B5+TB7)) */
1890 fp4 = packFloatx80(0, 0x3FFA, LIT64(0xAAAAAAAAAAAAAB5E));
1891 fp2 = floatx80_add(fp2, fp4, status); /* B2+T(B4+T(B6+TB8)) */
1892 fp1 = floatx80_add(fp1, float32_to_floatx80(
1893 make_float32(0xBF000000), status),
1894 status); /* B1+T(B3+T(B5+TB7)) */
1895 fp0 = floatx80_mul(fp0, fp2, status); /* S(B2+T(B4+T(B6+TB8))) */
1896 fp0 = floatx80_add(fp0, fp1, status);
1897 /* [B1+T(B3+T(B5+TB7))]+[S(B2+T(B4+T(B6+TB8)))] */
1899 x = packFloatx80(xSign, xExp, xSig);
1900 fp0 = floatx80_mul(fp0, x, status);
1902 status->float_rounding_mode = user_rnd_mode;
1903 status->floatx80_rounding_precision = user_rnd_prec;
1905 a = floatx80_add(fp0, float32_to_floatx80(posneg1, status), status);
1907 float_raise(float_flag_inexact, status);
1912 xSign = extractFloatx80Sign(fp0); /* X IS R */
1913 xExp = extractFloatx80Exp(fp0);
1914 xSig = extractFloatx80Frac(fp0);
1916 xSign ^= ((n + 1) >> 1) & 1; /* X IS NOW R'= SGN*R */
1918 fp0 = floatx80_mul(fp0, fp0, status); /* FP0 IS S */
1919 fp1 = floatx80_mul(fp0, fp0, status); /* FP1 IS T */
1920 fp3 = float64_to_floatx80(make_float64(0xBD6AAA77CCC994F5),
1922 fp2 = float64_to_floatx80(make_float64(0x3DE612097AAE8DA1),
1924 fp3 = floatx80_mul(fp3, fp1, status); /* T*A7 */
1925 fp2 = floatx80_mul(fp2, fp1, status); /* T*A6 */
1926 fp3 = floatx80_add(fp3, float64_to_floatx80(
1927 make_float64(0xBE5AE6452A118AE4), status),
1928 status); /* A5+T*A7 */
1929 fp2 = floatx80_add(fp2, float64_to_floatx80(
1930 make_float64(0x3EC71DE3A5341531), status),
1931 status); /* A4+T*A6 */
1932 fp3 = floatx80_mul(fp3, fp1, status); /* T(A5+TA7) */
1933 fp2 = floatx80_mul(fp2, fp1, status); /* T(A4+TA6) */
1934 fp3 = floatx80_add(fp3, float64_to_floatx80(
1935 make_float64(0xBF2A01A01A018B59), status),
1936 status); /* A3+T(A5+TA7) */
1937 fp4 = packFloatx80(0, 0x3FF8, LIT64(0x88888888888859AF));
1938 fp2 = floatx80_add(fp2, fp4, status); /* A2+T(A4+TA6) */
1939 fp1 = floatx80_mul(fp1, fp3, status); /* T(A3+T(A5+TA7)) */
1940 fp2 = floatx80_mul(fp2, fp0, status); /* S(A2+T(A4+TA6)) */
1941 fp4 = packFloatx80(1, 0x3FFC, LIT64(0xAAAAAAAAAAAAAA99));
1942 fp1 = floatx80_add(fp1, fp4, status); /* A1+T(A3+T(A5+TA7)) */
1943 fp1 = floatx80_add(fp1, fp2, status);
1944 /* [A1+T(A3+T(A5+TA7))]+[S(A2+T(A4+TA6))] */
1946 x = packFloatx80(xSign, xExp, xSig);
1947 fp0 = floatx80_mul(fp0, x, status); /* R'*S */
1948 fp0 = floatx80_mul(fp0, fp1, status); /* SIN(R')-R' */
1950 status->float_rounding_mode = user_rnd_mode;
1951 status->floatx80_rounding_precision = user_rnd_prec;
1953 a = floatx80_add(fp0, x, status);
1955 float_raise(float_flag_inexact, status);
1962 /*----------------------------------------------------------------------------
1964 *----------------------------------------------------------------------------*/
1966 floatx80 floatx80_atan(floatx80 a, float_status *status)
1972 int8_t user_rnd_mode, user_rnd_prec;
1974 int32_t compact, tbl_index;
1975 floatx80 fp0, fp1, fp2, fp3, xsave;
1977 aSig = extractFloatx80Frac(a);
1978 aExp = extractFloatx80Exp(a);
1979 aSign = extractFloatx80Sign(a);
1981 if (aExp == 0x7FFF) {
1982 if ((uint64_t) (aSig << 1)) {
1983 return propagateFloatx80NaNOneArg(a, status);
1985 a = packFloatx80(aSign, piby2_exp, pi_sig);
1986 float_raise(float_flag_inexact, status);
1987 return floatx80_move(a, status);
1990 if (aExp == 0 && aSig == 0) {
1991 return packFloatx80(aSign, 0, 0);
1994 compact = floatx80_make_compact(aExp, aSig);
1996 user_rnd_mode = status->float_rounding_mode;
1997 user_rnd_prec = status->floatx80_rounding_precision;
1998 status->float_rounding_mode = float_round_nearest_even;
1999 status->floatx80_rounding_precision = 80;
2001 if (compact < 0x3FFB8000 || compact > 0x4002FFFF) {
2002 /* |X| >= 16 or |X| < 1/16 */
2003 if (compact > 0x3FFF8000) { /* |X| >= 16 */
2004 if (compact > 0x40638000) { /* |X| > 2^(100) */
2005 fp0 = packFloatx80(aSign, piby2_exp, pi_sig);
2006 fp1 = packFloatx80(aSign, 0x0001, one_sig);
2008 status->float_rounding_mode = user_rnd_mode;
2009 status->floatx80_rounding_precision = user_rnd_prec;
2011 a = floatx80_sub(fp0, fp1, status);
2013 float_raise(float_flag_inexact, status);
2018 fp1 = packFloatx80(1, one_exp, one_sig); /* -1 */
2019 fp1 = floatx80_div(fp1, fp0, status); /* X' = -1/X */
2021 fp0 = floatx80_mul(fp1, fp1, status); /* Y = X'*X' */
2022 fp1 = floatx80_mul(fp0, fp0, status); /* Z = Y*Y */
2023 fp3 = float64_to_floatx80(make_float64(0xBFB70BF398539E6A),
2025 fp2 = float64_to_floatx80(make_float64(0x3FBC7187962D1D7D),
2027 fp3 = floatx80_mul(fp3, fp1, status); /* Z*C5 */
2028 fp2 = floatx80_mul(fp2, fp1, status); /* Z*C4 */
2029 fp3 = floatx80_add(fp3, float64_to_floatx80(
2030 make_float64(0xBFC24924827107B8), status),
2031 status); /* C3+Z*C5 */
2032 fp2 = floatx80_add(fp2, float64_to_floatx80(
2033 make_float64(0x3FC999999996263E), status),
2034 status); /* C2+Z*C4 */
2035 fp1 = floatx80_mul(fp1, fp3, status); /* Z*(C3+Z*C5) */
2036 fp2 = floatx80_mul(fp2, fp0, status); /* Y*(C2+Z*C4) */
2037 fp1 = floatx80_add(fp1, float64_to_floatx80(
2038 make_float64(0xBFD5555555555536), status),
2039 status); /* C1+Z*(C3+Z*C5) */
2040 fp0 = floatx80_mul(fp0, xsave, status); /* X'*Y */
2041 /* [Y*(C2+Z*C4)]+[C1+Z*(C3+Z*C5)] */
2042 fp1 = floatx80_add(fp1, fp2, status);
2043 /* X'*Y*([B1+Z*(B3+Z*B5)]+[Y*(B2+Z*(B4+Z*B6))]) ?? */
2044 fp0 = floatx80_mul(fp0, fp1, status);
2045 fp0 = floatx80_add(fp0, xsave, status);
2046 fp1 = packFloatx80(aSign, piby2_exp, pi_sig);
2048 status->float_rounding_mode = user_rnd_mode;
2049 status->floatx80_rounding_precision = user_rnd_prec;
2051 a = floatx80_add(fp0, fp1, status);
2053 float_raise(float_flag_inexact, status);
2057 } else { /* |X| < 1/16 */
2058 if (compact < 0x3FD78000) { /* |X| < 2^(-40) */
2059 status->float_rounding_mode = user_rnd_mode;
2060 status->floatx80_rounding_precision = user_rnd_prec;
2062 a = floatx80_move(a, status);
2064 float_raise(float_flag_inexact, status);
2070 fp0 = floatx80_mul(fp0, fp0, status); /* Y = X*X */
2071 fp1 = floatx80_mul(fp0, fp0, status); /* Z = Y*Y */
2072 fp2 = float64_to_floatx80(make_float64(0x3FB344447F876989),
2074 fp3 = float64_to_floatx80(make_float64(0xBFB744EE7FAF45DB),
2076 fp2 = floatx80_mul(fp2, fp1, status); /* Z*B6 */
2077 fp3 = floatx80_mul(fp3, fp1, status); /* Z*B5 */
2078 fp2 = floatx80_add(fp2, float64_to_floatx80(
2079 make_float64(0x3FBC71C646940220), status),
2080 status); /* B4+Z*B6 */
2081 fp3 = floatx80_add(fp3, float64_to_floatx80(
2082 make_float64(0xBFC24924921872F9),
2083 status), status); /* B3+Z*B5 */
2084 fp2 = floatx80_mul(fp2, fp1, status); /* Z*(B4+Z*B6) */
2085 fp1 = floatx80_mul(fp1, fp3, status); /* Z*(B3+Z*B5) */
2086 fp2 = floatx80_add(fp2, float64_to_floatx80(
2087 make_float64(0x3FC9999999998FA9), status),
2088 status); /* B2+Z*(B4+Z*B6) */
2089 fp1 = floatx80_add(fp1, float64_to_floatx80(
2090 make_float64(0xBFD5555555555555), status),
2091 status); /* B1+Z*(B3+Z*B5) */
2092 fp2 = floatx80_mul(fp2, fp0, status); /* Y*(B2+Z*(B4+Z*B6)) */
2093 fp0 = floatx80_mul(fp0, xsave, status); /* X*Y */
2094 /* [B1+Z*(B3+Z*B5)]+[Y*(B2+Z*(B4+Z*B6))] */
2095 fp1 = floatx80_add(fp1, fp2, status);
2096 /* X*Y*([B1+Z*(B3+Z*B5)]+[Y*(B2+Z*(B4+Z*B6))]) */
2097 fp0 = floatx80_mul(fp0, fp1, status);
2099 status->float_rounding_mode = user_rnd_mode;
2100 status->floatx80_rounding_precision = user_rnd_prec;
2102 a = floatx80_add(fp0, xsave, status);
2104 float_raise(float_flag_inexact, status);
2110 aSig &= LIT64(0xF800000000000000);
2111 aSig |= LIT64(0x0400000000000000);
2112 xsave = packFloatx80(aSign, aExp, aSig); /* F */
2115 fp2 = packFloatx80(0, one_exp, one_sig); /* 1 */
2116 fp1 = floatx80_mul(fp1, xsave, status); /* X*F */
2117 fp0 = floatx80_sub(fp0, xsave, status); /* X-F */
2118 fp1 = floatx80_add(fp1, fp2, status); /* 1 + X*F */
2119 fp0 = floatx80_div(fp0, fp1, status); /* U = (X-F)/(1+X*F) */
2121 tbl_index = compact;
2123 tbl_index &= 0x7FFF0000;
2124 tbl_index -= 0x3FFB0000;
2126 tbl_index += compact & 0x00007800;
2129 fp3 = atan_tbl[tbl_index];
2131 fp3.high |= aSign ? 0x8000 : 0; /* ATAN(F) */
2133 fp1 = floatx80_mul(fp0, fp0, status); /* V = U*U */
2134 fp2 = float64_to_floatx80(make_float64(0xBFF6687E314987D8),
2136 fp2 = floatx80_add(fp2, fp1, status); /* A3+V */
2137 fp2 = floatx80_mul(fp2, fp1, status); /* V*(A3+V) */
2138 fp1 = floatx80_mul(fp1, fp0, status); /* U*V */
2139 fp2 = floatx80_add(fp2, float64_to_floatx80(
2140 make_float64(0x4002AC6934A26DB3), status),
2141 status); /* A2+V*(A3+V) */
2142 fp1 = floatx80_mul(fp1, float64_to_floatx80(
2143 make_float64(0xBFC2476F4E1DA28E), status),
2144 status); /* A1+U*V */
2145 fp1 = floatx80_mul(fp1, fp2, status); /* A1*U*V*(A2+V*(A3+V)) */
2146 fp0 = floatx80_add(fp0, fp1, status); /* ATAN(U) */
2148 status->float_rounding_mode = user_rnd_mode;
2149 status->floatx80_rounding_precision = user_rnd_prec;
2151 a = floatx80_add(fp0, fp3, status); /* ATAN(X) */
2153 float_raise(float_flag_inexact, status);
2159 /*----------------------------------------------------------------------------
2161 *----------------------------------------------------------------------------*/
2163 floatx80 floatx80_asin(floatx80 a, float_status *status)
2169 int8_t user_rnd_mode, user_rnd_prec;
2172 floatx80 fp0, fp1, fp2, one;
2174 aSig = extractFloatx80Frac(a);
2175 aExp = extractFloatx80Exp(a);
2176 aSign = extractFloatx80Sign(a);
2178 if (aExp == 0x7FFF && (uint64_t) (aSig << 1)) {
2179 return propagateFloatx80NaNOneArg(a, status);
2182 if (aExp == 0 && aSig == 0) {
2183 return packFloatx80(aSign, 0, 0);
2186 compact = floatx80_make_compact(aExp, aSig);
2188 if (compact >= 0x3FFF8000) { /* |X| >= 1 */
2189 if (aExp == one_exp && aSig == one_sig) { /* |X| == 1 */
2190 float_raise(float_flag_inexact, status);
2191 a = packFloatx80(aSign, piby2_exp, pi_sig);
2192 return floatx80_move(a, status);
2193 } else { /* |X| > 1 */
2194 float_raise(float_flag_invalid, status);
2195 return floatx80_default_nan(status);
2200 user_rnd_mode = status->float_rounding_mode;
2201 user_rnd_prec = status->floatx80_rounding_precision;
2202 status->float_rounding_mode = float_round_nearest_even;
2203 status->floatx80_rounding_precision = 80;
2205 one = packFloatx80(0, one_exp, one_sig);
2208 fp1 = floatx80_sub(one, fp0, status); /* 1 - X */
2209 fp2 = floatx80_add(one, fp0, status); /* 1 + X */
2210 fp1 = floatx80_mul(fp2, fp1, status); /* (1+X)*(1-X) */
2211 fp1 = floatx80_sqrt(fp1, status); /* SQRT((1+X)*(1-X)) */
2212 fp0 = floatx80_div(fp0, fp1, status); /* X/SQRT((1+X)*(1-X)) */
2214 status->float_rounding_mode = user_rnd_mode;
2215 status->floatx80_rounding_precision = user_rnd_prec;
2217 a = floatx80_atan(fp0, status); /* ATAN(X/SQRT((1+X)*(1-X))) */
2219 float_raise(float_flag_inexact, status);
2224 /*----------------------------------------------------------------------------
2226 *----------------------------------------------------------------------------*/
2228 floatx80 floatx80_acos(floatx80 a, float_status *status)
2234 int8_t user_rnd_mode, user_rnd_prec;
2237 floatx80 fp0, fp1, one;
2239 aSig = extractFloatx80Frac(a);
2240 aExp = extractFloatx80Exp(a);
2241 aSign = extractFloatx80Sign(a);
2243 if (aExp == 0x7FFF && (uint64_t) (aSig << 1)) {
2244 return propagateFloatx80NaNOneArg(a, status);
2246 if (aExp == 0 && aSig == 0) {
2247 float_raise(float_flag_inexact, status);
2248 return roundAndPackFloatx80(status->floatx80_rounding_precision, 0,
2249 piby2_exp, pi_sig, 0, status);
2252 compact = floatx80_make_compact(aExp, aSig);
2254 if (compact >= 0x3FFF8000) { /* |X| >= 1 */
2255 if (aExp == one_exp && aSig == one_sig) { /* |X| == 1 */
2256 if (aSign) { /* X == -1 */
2257 a = packFloatx80(0, pi_exp, pi_sig);
2258 float_raise(float_flag_inexact, status);
2259 return floatx80_move(a, status);
2260 } else { /* X == +1 */
2261 return packFloatx80(0, 0, 0);
2263 } else { /* |X| > 1 */
2264 float_raise(float_flag_invalid, status);
2265 return floatx80_default_nan(status);
2269 user_rnd_mode = status->float_rounding_mode;
2270 user_rnd_prec = status->floatx80_rounding_precision;
2271 status->float_rounding_mode = float_round_nearest_even;
2272 status->floatx80_rounding_precision = 80;
2274 one = packFloatx80(0, one_exp, one_sig);
2277 fp1 = floatx80_add(one, fp0, status); /* 1 + X */
2278 fp0 = floatx80_sub(one, fp0, status); /* 1 - X */
2279 fp0 = floatx80_div(fp0, fp1, status); /* (1-X)/(1+X) */
2280 fp0 = floatx80_sqrt(fp0, status); /* SQRT((1-X)/(1+X)) */
2281 fp0 = floatx80_atan(fp0, status); /* ATAN(SQRT((1-X)/(1+X))) */
2283 status->float_rounding_mode = user_rnd_mode;
2284 status->floatx80_rounding_precision = user_rnd_prec;
2286 a = floatx80_add(fp0, fp0, status); /* 2 * ATAN(SQRT((1-X)/(1+X))) */
2288 float_raise(float_flag_inexact, status);
2293 /*----------------------------------------------------------------------------
2294 | Hyperbolic arc tangent
2295 *----------------------------------------------------------------------------*/
2297 floatx80 floatx80_atanh(floatx80 a, float_status *status)
2303 int8_t user_rnd_mode, user_rnd_prec;
2306 floatx80 fp0, fp1, fp2, one;
2308 aSig = extractFloatx80Frac(a);
2309 aExp = extractFloatx80Exp(a);
2310 aSign = extractFloatx80Sign(a);
2312 if (aExp == 0x7FFF && (uint64_t) (aSig << 1)) {
2313 return propagateFloatx80NaNOneArg(a, status);
2316 if (aExp == 0 && aSig == 0) {
2317 return packFloatx80(aSign, 0, 0);
2320 compact = floatx80_make_compact(aExp, aSig);
2322 if (compact >= 0x3FFF8000) { /* |X| >= 1 */
2323 if (aExp == one_exp && aSig == one_sig) { /* |X| == 1 */
2324 float_raise(float_flag_divbyzero, status);
2325 return packFloatx80(aSign, floatx80_infinity.high,
2326 floatx80_infinity.low);
2327 } else { /* |X| > 1 */
2328 float_raise(float_flag_invalid, status);
2329 return floatx80_default_nan(status);
2333 user_rnd_mode = status->float_rounding_mode;
2334 user_rnd_prec = status->floatx80_rounding_precision;
2335 status->float_rounding_mode = float_round_nearest_even;
2336 status->floatx80_rounding_precision = 80;
2338 one = packFloatx80(0, one_exp, one_sig);
2339 fp2 = packFloatx80(aSign, 0x3FFE, one_sig); /* SIGN(X) * (1/2) */
2340 fp0 = packFloatx80(0, aExp, aSig); /* Y = |X| */
2341 fp1 = packFloatx80(1, aExp, aSig); /* -Y */
2342 fp0 = floatx80_add(fp0, fp0, status); /* 2Y */
2343 fp1 = floatx80_add(fp1, one, status); /* 1-Y */
2344 fp0 = floatx80_div(fp0, fp1, status); /* Z = 2Y/(1-Y) */
2345 fp0 = floatx80_lognp1(fp0, status); /* LOG1P(Z) */
2347 status->float_rounding_mode = user_rnd_mode;
2348 status->floatx80_rounding_precision = user_rnd_prec;
2350 a = floatx80_mul(fp0, fp2,
2351 status); /* ATANH(X) = SIGN(X) * (1/2) * LOG1P(Z) */
2353 float_raise(float_flag_inexact, status);
2358 /*----------------------------------------------------------------------------
2360 *----------------------------------------------------------------------------*/
2362 floatx80 floatx80_etoxm1(floatx80 a, float_status *status)
2368 int8_t user_rnd_mode, user_rnd_prec;
2370 int32_t compact, n, j, m, m1;
2371 floatx80 fp0, fp1, fp2, fp3, l2, sc, onebysc;
2373 aSig = extractFloatx80Frac(a);
2374 aExp = extractFloatx80Exp(a);
2375 aSign = extractFloatx80Sign(a);
2377 if (aExp == 0x7FFF) {
2378 if ((uint64_t) (aSig << 1)) {
2379 return propagateFloatx80NaNOneArg(a, status);
2382 return packFloatx80(aSign, one_exp, one_sig);
2384 return packFloatx80(0, floatx80_infinity.high,
2385 floatx80_infinity.low);
2388 if (aExp == 0 && aSig == 0) {
2389 return packFloatx80(aSign, 0, 0);
2392 user_rnd_mode = status->float_rounding_mode;
2393 user_rnd_prec = status->floatx80_rounding_precision;
2394 status->float_rounding_mode = float_round_nearest_even;
2395 status->floatx80_rounding_precision = 80;
2397 if (aExp >= 0x3FFD) { /* |X| >= 1/4 */
2398 compact = floatx80_make_compact(aExp, aSig);
2400 if (compact <= 0x4004C215) { /* |X| <= 70 log2 */
2403 fp0 = floatx80_mul(fp0, float32_to_floatx80(
2404 make_float32(0x42B8AA3B), status),
2405 status); /* 64/log2 * X */
2406 n = floatx80_to_int32(fp0, status); /* int(64/log2*X) */
2407 fp0 = int32_to_floatx80(n, status);
2409 j = n & 0x3F; /* J = N mod 64 */
2410 m = n / 64; /* NOTE: this is really arithmetic right shift by 6 */
2412 /* arithmetic right shift is division and
2413 * round towards minus infinity
2418 /*m += 0x3FFF; // biased exponent of 2^(M) */
2419 /*m1 += 0x3FFF; // biased exponent of -2^(-M) */
2422 fp0 = floatx80_mul(fp0, float32_to_floatx80(
2423 make_float32(0xBC317218), status),
2424 status); /* N * L1, L1 = lead(-log2/64) */
2425 l2 = packFloatx80(0, 0x3FDC, LIT64(0x82E308654361C4C6));
2426 fp2 = floatx80_mul(fp2, l2, status); /* N * L2, L1+L2 = -log2/64 */
2427 fp0 = floatx80_add(fp0, fp1, status); /* X + N*L1 */
2428 fp0 = floatx80_add(fp0, fp2, status); /* R */
2430 fp1 = floatx80_mul(fp0, fp0, status); /* S = R*R */
2431 fp2 = float32_to_floatx80(make_float32(0x3950097B),
2433 fp2 = floatx80_mul(fp2, fp1, status); /* fp2 is S*A6 */
2434 fp3 = floatx80_mul(float32_to_floatx80(make_float32(0x3AB60B6A),
2435 status), fp1, status); /* fp3 is S*A5 */
2436 fp2 = floatx80_add(fp2, float64_to_floatx80(
2437 make_float64(0x3F81111111174385), status),
2438 status); /* fp2 IS A4+S*A6 */
2439 fp3 = floatx80_add(fp3, float64_to_floatx80(
2440 make_float64(0x3FA5555555554F5A), status),
2441 status); /* fp3 is A3+S*A5 */
2442 fp2 = floatx80_mul(fp2, fp1, status); /* fp2 IS S*(A4+S*A6) */
2443 fp3 = floatx80_mul(fp3, fp1, status); /* fp3 IS S*(A3+S*A5) */
2444 fp2 = floatx80_add(fp2, float64_to_floatx80(
2445 make_float64(0x3FC5555555555555), status),
2446 status); /* fp2 IS A2+S*(A4+S*A6) */
2447 fp3 = floatx80_add(fp3, float32_to_floatx80(
2448 make_float32(0x3F000000), status),
2449 status); /* fp3 IS A1+S*(A3+S*A5) */
2450 fp2 = floatx80_mul(fp2, fp1,
2451 status); /* fp2 IS S*(A2+S*(A4+S*A6)) */
2452 fp1 = floatx80_mul(fp1, fp3,
2453 status); /* fp1 IS S*(A1+S*(A3+S*A5)) */
2454 fp2 = floatx80_mul(fp2, fp0,
2455 status); /* fp2 IS R*S*(A2+S*(A4+S*A6)) */
2456 fp0 = floatx80_add(fp0, fp1,
2457 status); /* fp0 IS R+S*(A1+S*(A3+S*A5)) */
2458 fp0 = floatx80_add(fp0, fp2, status); /* fp0 IS EXP(R) - 1 */
2460 fp0 = floatx80_mul(fp0, exp_tbl[j],
2461 status); /* 2^(J/64)*(Exp(R)-1) */
2464 fp1 = float32_to_floatx80(exp_tbl2[j], status);
2465 onebysc = packFloatx80(1, m1 + 0x3FFF, one_sig); /* -2^(-M) */
2466 fp1 = floatx80_add(fp1, onebysc, status);
2467 fp0 = floatx80_add(fp0, fp1, status);
2468 fp0 = floatx80_add(fp0, exp_tbl[j], status);
2469 } else if (m < -3) {
2470 fp0 = floatx80_add(fp0, float32_to_floatx80(exp_tbl2[j],
2472 fp0 = floatx80_add(fp0, exp_tbl[j], status);
2473 onebysc = packFloatx80(1, m1 + 0x3FFF, one_sig); /* -2^(-M) */
2474 fp0 = floatx80_add(fp0, onebysc, status);
2475 } else { /* -3 <= m <= 63 */
2477 fp0 = floatx80_add(fp0, float32_to_floatx80(exp_tbl2[j],
2479 onebysc = packFloatx80(1, m1 + 0x3FFF, one_sig); /* -2^(-M) */
2480 fp1 = floatx80_add(fp1, onebysc, status);
2481 fp0 = floatx80_add(fp0, fp1, status);
2484 sc = packFloatx80(0, m + 0x3FFF, one_sig);
2486 status->float_rounding_mode = user_rnd_mode;
2487 status->floatx80_rounding_precision = user_rnd_prec;
2489 a = floatx80_mul(fp0, sc, status);
2491 float_raise(float_flag_inexact, status);
2494 } else { /* |X| > 70 log2 */
2496 fp0 = float32_to_floatx80(make_float32(0xBF800000),
2499 status->float_rounding_mode = user_rnd_mode;
2500 status->floatx80_rounding_precision = user_rnd_prec;
2502 a = floatx80_add(fp0, float32_to_floatx80(
2503 make_float32(0x00800000), status),
2504 status); /* -1 + 2^(-126) */
2506 float_raise(float_flag_inexact, status);
2510 status->float_rounding_mode = user_rnd_mode;
2511 status->floatx80_rounding_precision = user_rnd_prec;
2513 return floatx80_etox(a, status);
2516 } else { /* |X| < 1/4 */
2517 if (aExp >= 0x3FBE) {
2519 fp0 = floatx80_mul(fp0, fp0, status); /* S = X*X */
2520 fp1 = float32_to_floatx80(make_float32(0x2F30CAA8),
2522 fp1 = floatx80_mul(fp1, fp0, status); /* S * B12 */
2523 fp2 = float32_to_floatx80(make_float32(0x310F8290),
2525 fp1 = floatx80_add(fp1, float32_to_floatx80(
2526 make_float32(0x32D73220), status),
2528 fp2 = floatx80_mul(fp2, fp0, status);
2529 fp1 = floatx80_mul(fp1, fp0, status);
2530 fp2 = floatx80_add(fp2, float32_to_floatx80(
2531 make_float32(0x3493F281), status),
2533 fp1 = floatx80_add(fp1, float64_to_floatx80(
2534 make_float64(0x3EC71DE3A5774682), status),
2536 fp2 = floatx80_mul(fp2, fp0, status);
2537 fp1 = floatx80_mul(fp1, fp0, status);
2538 fp2 = floatx80_add(fp2, float64_to_floatx80(
2539 make_float64(0x3EFA01A019D7CB68), status),
2541 fp1 = floatx80_add(fp1, float64_to_floatx80(
2542 make_float64(0x3F2A01A01A019DF3), status),
2544 fp2 = floatx80_mul(fp2, fp0, status);
2545 fp1 = floatx80_mul(fp1, fp0, status);
2546 fp2 = floatx80_add(fp2, float64_to_floatx80(
2547 make_float64(0x3F56C16C16C170E2), status),
2549 fp1 = floatx80_add(fp1, float64_to_floatx80(
2550 make_float64(0x3F81111111111111), status),
2552 fp2 = floatx80_mul(fp2, fp0, status);
2553 fp1 = floatx80_mul(fp1, fp0, status);
2554 fp2 = floatx80_add(fp2, float64_to_floatx80(
2555 make_float64(0x3FA5555555555555), status),
2557 fp3 = packFloatx80(0, 0x3FFC, LIT64(0xAAAAAAAAAAAAAAAB));
2558 fp1 = floatx80_add(fp1, fp3, status); /* B2 */
2559 fp2 = floatx80_mul(fp2, fp0, status);
2560 fp1 = floatx80_mul(fp1, fp0, status);
2562 fp2 = floatx80_mul(fp2, fp0, status);
2563 fp1 = floatx80_mul(fp1, a, status);
2565 fp0 = floatx80_mul(fp0, float32_to_floatx80(
2566 make_float32(0x3F000000), status),
2568 fp1 = floatx80_add(fp1, fp2, status); /* Q */
2569 fp0 = floatx80_add(fp0, fp1, status); /* S*B1+Q */
2571 status->float_rounding_mode = user_rnd_mode;
2572 status->floatx80_rounding_precision = user_rnd_prec;
2574 a = floatx80_add(fp0, a, status);
2576 float_raise(float_flag_inexact, status);
2579 } else { /* |X| < 2^(-65) */
2580 sc = packFloatx80(1, 1, one_sig);
2583 if (aExp < 0x0033) { /* |X| < 2^(-16382) */
2584 fp0 = floatx80_mul(fp0, float64_to_floatx80(
2585 make_float64(0x48B0000000000000), status),
2587 fp0 = floatx80_add(fp0, sc, status);
2589 status->float_rounding_mode = user_rnd_mode;
2590 status->floatx80_rounding_precision = user_rnd_prec;
2592 a = floatx80_mul(fp0, float64_to_floatx80(
2593 make_float64(0x3730000000000000), status),
2596 status->float_rounding_mode = user_rnd_mode;
2597 status->floatx80_rounding_precision = user_rnd_prec;
2599 a = floatx80_add(fp0, sc, status);
2602 float_raise(float_flag_inexact, status);
2609 /*----------------------------------------------------------------------------
2610 | Hyperbolic tangent
2611 *----------------------------------------------------------------------------*/
2613 floatx80 floatx80_tanh(floatx80 a, float_status *status)
2617 uint64_t aSig, vSig;
2619 int8_t user_rnd_mode, user_rnd_prec;
2625 aSig = extractFloatx80Frac(a);
2626 aExp = extractFloatx80Exp(a);
2627 aSign = extractFloatx80Sign(a);
2629 if (aExp == 0x7FFF) {
2630 if ((uint64_t) (aSig << 1)) {
2631 return propagateFloatx80NaNOneArg(a, status);
2633 return packFloatx80(aSign, one_exp, one_sig);
2636 if (aExp == 0 && aSig == 0) {
2637 return packFloatx80(aSign, 0, 0);
2640 user_rnd_mode = status->float_rounding_mode;
2641 user_rnd_prec = status->floatx80_rounding_precision;
2642 status->float_rounding_mode = float_round_nearest_even;
2643 status->floatx80_rounding_precision = 80;
2645 compact = floatx80_make_compact(aExp, aSig);
2647 if (compact < 0x3FD78000 || compact > 0x3FFFDDCE) {
2649 if (compact < 0x3FFF8000) {
2651 status->float_rounding_mode = user_rnd_mode;
2652 status->floatx80_rounding_precision = user_rnd_prec;
2654 a = floatx80_move(a, status);
2656 float_raise(float_flag_inexact, status);
2660 if (compact > 0x40048AA1) {
2663 sign |= aSign ? 0x80000000 : 0x00000000;
2664 fp0 = float32_to_floatx80(make_float32(sign), status);
2666 sign ^= 0x80800000; /* -SIGN(X)*EPS */
2668 status->float_rounding_mode = user_rnd_mode;
2669 status->floatx80_rounding_precision = user_rnd_prec;
2671 a = floatx80_add(fp0, float32_to_floatx80(make_float32(sign),
2674 float_raise(float_flag_inexact, status);
2678 fp0 = packFloatx80(0, aExp + 1, aSig); /* Y = 2|X| */
2679 fp0 = floatx80_etox(fp0, status); /* FP0 IS EXP(Y) */
2680 fp0 = floatx80_add(fp0, float32_to_floatx80(
2681 make_float32(0x3F800000),
2682 status), status); /* EXP(Y)+1 */
2683 sign = aSign ? 0x80000000 : 0x00000000;
2684 fp1 = floatx80_div(float32_to_floatx80(make_float32(
2685 sign ^ 0xC0000000), status), fp0,
2686 status); /* -SIGN(X)*2 / [EXP(Y)+1] */
2687 fp0 = float32_to_floatx80(make_float32(sign | 0x3F800000),
2690 status->float_rounding_mode = user_rnd_mode;
2691 status->floatx80_rounding_precision = user_rnd_prec;
2693 a = floatx80_add(fp1, fp0, status);
2695 float_raise(float_flag_inexact, status);
2700 } else { /* 2**(-40) < |X| < (5/2)LOG2 */
2701 fp0 = packFloatx80(0, aExp + 1, aSig); /* Y = 2|X| */
2702 fp0 = floatx80_etoxm1(fp0, status); /* FP0 IS Z = EXPM1(Y) */
2703 fp1 = floatx80_add(fp0, float32_to_floatx80(make_float32(0x40000000),
2707 vSign = extractFloatx80Sign(fp1);
2708 vExp = extractFloatx80Exp(fp1);
2709 vSig = extractFloatx80Frac(fp1);
2711 fp1 = packFloatx80(vSign ^ aSign, vExp, vSig);
2713 status->float_rounding_mode = user_rnd_mode;
2714 status->floatx80_rounding_precision = user_rnd_prec;
2716 a = floatx80_div(fp0, fp1, status);
2718 float_raise(float_flag_inexact, status);
2724 /*----------------------------------------------------------------------------
2726 *----------------------------------------------------------------------------*/
2728 floatx80 floatx80_sinh(floatx80 a, float_status *status)
2734 int8_t user_rnd_mode, user_rnd_prec;
2737 floatx80 fp0, fp1, fp2;
2740 aSig = extractFloatx80Frac(a);
2741 aExp = extractFloatx80Exp(a);
2742 aSign = extractFloatx80Sign(a);
2744 if (aExp == 0x7FFF) {
2745 if ((uint64_t) (aSig << 1)) {
2746 return propagateFloatx80NaNOneArg(a, status);
2748 return packFloatx80(aSign, floatx80_infinity.high,
2749 floatx80_infinity.low);
2752 if (aExp == 0 && aSig == 0) {
2753 return packFloatx80(aSign, 0, 0);
2756 user_rnd_mode = status->float_rounding_mode;
2757 user_rnd_prec = status->floatx80_rounding_precision;
2758 status->float_rounding_mode = float_round_nearest_even;
2759 status->floatx80_rounding_precision = 80;
2761 compact = floatx80_make_compact(aExp, aSig);
2763 if (compact > 0x400CB167) {
2765 if (compact > 0x400CB2B3) {
2766 status->float_rounding_mode = user_rnd_mode;
2767 status->floatx80_rounding_precision = user_rnd_prec;
2769 return roundAndPackFloatx80(status->floatx80_rounding_precision,
2770 aSign, 0x8000, aSig, 0, status);
2772 fp0 = floatx80_abs(a); /* Y = |X| */
2773 fp0 = floatx80_sub(fp0, float64_to_floatx80(
2774 make_float64(0x40C62D38D3D64634), status),
2775 status); /* (|X|-16381LOG2_LEAD) */
2776 fp0 = floatx80_sub(fp0, float64_to_floatx80(
2777 make_float64(0x3D6F90AEB1E75CC7), status),
2778 status); /* |X| - 16381 LOG2, ACCURATE */
2779 fp0 = floatx80_etox(fp0, status);
2780 fp2 = packFloatx80(aSign, 0x7FFB, one_sig);
2782 status->float_rounding_mode = user_rnd_mode;
2783 status->floatx80_rounding_precision = user_rnd_prec;
2785 a = floatx80_mul(fp0, fp2, status);
2787 float_raise(float_flag_inexact, status);
2791 } else { /* |X| < 16380 LOG2 */
2792 fp0 = floatx80_abs(a); /* Y = |X| */
2793 fp0 = floatx80_etoxm1(fp0, status); /* FP0 IS Z = EXPM1(Y) */
2794 fp1 = floatx80_add(fp0, float32_to_floatx80(make_float32(0x3F800000),
2795 status), status); /* 1+Z */
2797 fp0 = floatx80_div(fp0, fp1, status); /* Z/(1+Z) */
2798 fp0 = floatx80_add(fp0, fp2, status);
2800 fact = packFloat32(aSign, 0x7E, 0);
2802 status->float_rounding_mode = user_rnd_mode;
2803 status->floatx80_rounding_precision = user_rnd_prec;
2805 a = floatx80_mul(fp0, float32_to_floatx80(fact, status), status);
2807 float_raise(float_flag_inexact, status);
2813 /*----------------------------------------------------------------------------
2815 *----------------------------------------------------------------------------*/
2817 floatx80 floatx80_cosh(floatx80 a, float_status *status)
2822 int8_t user_rnd_mode, user_rnd_prec;
2827 aSig = extractFloatx80Frac(a);
2828 aExp = extractFloatx80Exp(a);
2830 if (aExp == 0x7FFF) {
2831 if ((uint64_t) (aSig << 1)) {
2832 return propagateFloatx80NaNOneArg(a, status);
2834 return packFloatx80(0, floatx80_infinity.high,
2835 floatx80_infinity.low);
2838 if (aExp == 0 && aSig == 0) {
2839 return packFloatx80(0, one_exp, one_sig);
2842 user_rnd_mode = status->float_rounding_mode;
2843 user_rnd_prec = status->floatx80_rounding_precision;
2844 status->float_rounding_mode = float_round_nearest_even;
2845 status->floatx80_rounding_precision = 80;
2847 compact = floatx80_make_compact(aExp, aSig);
2849 if (compact > 0x400CB167) {
2850 if (compact > 0x400CB2B3) {
2851 status->float_rounding_mode = user_rnd_mode;
2852 status->floatx80_rounding_precision = user_rnd_prec;
2853 return roundAndPackFloatx80(status->floatx80_rounding_precision, 0,
2854 0x8000, one_sig, 0, status);
2856 fp0 = packFloatx80(0, aExp, aSig);
2857 fp0 = floatx80_sub(fp0, float64_to_floatx80(
2858 make_float64(0x40C62D38D3D64634), status),
2860 fp0 = floatx80_sub(fp0, float64_to_floatx80(
2861 make_float64(0x3D6F90AEB1E75CC7), status),
2863 fp0 = floatx80_etox(fp0, status);
2864 fp1 = packFloatx80(0, 0x7FFB, one_sig);
2866 status->float_rounding_mode = user_rnd_mode;
2867 status->floatx80_rounding_precision = user_rnd_prec;
2869 a = floatx80_mul(fp0, fp1, status);
2871 float_raise(float_flag_inexact, status);
2877 fp0 = packFloatx80(0, aExp, aSig); /* |X| */
2878 fp0 = floatx80_etox(fp0, status); /* EXP(|X|) */
2879 fp0 = floatx80_mul(fp0, float32_to_floatx80(make_float32(0x3F000000),
2880 status), status); /* (1/2)*EXP(|X|) */
2881 fp1 = float32_to_floatx80(make_float32(0x3E800000), status); /* 1/4 */
2882 fp1 = floatx80_div(fp1, fp0, status); /* 1/(2*EXP(|X|)) */
2884 status->float_rounding_mode = user_rnd_mode;
2885 status->floatx80_rounding_precision = user_rnd_prec;
2887 a = floatx80_add(fp0, fp1, status);
2889 float_raise(float_flag_inexact, status);