Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20180323' into...
[qemu/ar7.git] / target / m68k / softfloat.c
blobdffb371c71e6865e55d0aa7c8f35e4129375ff02
1 /*
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
10 * the BSD license
11 * GPL-v2-or-later
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"
26 #define pi_exp 0x4000
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)
50 flag aSign, zSign;
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);
61 if (aExp == 0x7FFF) {
62 if ((uint64_t) (aSig0 << 1)
63 || ((bExp == 0x7FFF) && (uint64_t) (bSig << 1))) {
64 return propagateFloatx80NaN(a, b, status);
66 goto invalid;
68 if (bExp == 0x7FFF) {
69 if ((uint64_t) (bSig << 1)) {
70 return propagateFloatx80NaN(a, b, status);
72 return a;
74 if (bExp == 0) {
75 if (bSig == 0) {
76 invalid:
77 float_raise(float_flag_invalid, status);
78 return floatx80_default_nan(status);
80 normalizeFloatx80Subnormal(bSig, &bExp, &bSig);
82 if (aExp == 0) {
83 if ((uint64_t) (aSig0 << 1) == 0) {
84 return a;
86 normalizeFloatx80Subnormal(aSig0, &aExp, &aSig0);
88 bSig |= LIT64(0x8000000000000000);
89 zSign = aSign;
90 expDiff = aExp - bExp;
91 aSig1 = 0;
92 if (expDiff < 0) {
93 return a;
95 qTemp = (bSig <= aSig0);
96 if (qTemp) {
97 aSig0 -= bSig;
99 expDiff -= 64;
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);
107 expDiff += 64;
108 if (0 < expDiff) {
109 qTemp = estimateDiv128To64(aSig0, aSig1, bSig);
110 qTemp = (2 < qTemp) ? qTemp - 2 : 0;
111 qTemp >>= 64 - expDiff;
112 mul64To128(bSig, qTemp << (64 - expDiff), &term0, &term1);
113 sub128(aSig0, aSig1, term0, term1, &aSig0, &aSig1);
114 shortShift128Left(0, bSig, 64 - expDiff, &term0, &term1);
115 while (le128(term0, term1, aSig0, aSig1)) {
116 ++qTemp;
117 sub128(aSig0, aSig1, term0, term1, &aSig0, &aSig1);
120 return
121 normalizeRoundAndPackFloatx80(
122 80, zSign, bExp + expDiff, aSig0, aSig1, status);
125 /*----------------------------------------------------------------------------
126 | Returns the mantissa of the extended double-precision floating-point
127 | value `a'.
128 *----------------------------------------------------------------------------*/
130 floatx80 floatx80_getman(floatx80 a, float_status *status)
132 flag aSign;
133 int32_t aExp;
134 uint64_t aSig;
136 aSig = extractFloatx80Frac(a);
137 aExp = extractFloatx80Exp(a);
138 aSign = extractFloatx80Sign(a);
140 if (aExp == 0x7FFF) {
141 if ((uint64_t) (aSig << 1)) {
142 return propagateFloatx80NaNOneArg(a , status);
144 float_raise(float_flag_invalid , status);
145 return floatx80_default_nan(status);
148 if (aExp == 0) {
149 if (aSig == 0) {
150 return packFloatx80(aSign, 0, 0);
152 normalizeFloatx80Subnormal(aSig, &aExp, &aSig);
155 return roundAndPackFloatx80(status->floatx80_rounding_precision, aSign,
156 0x3FFF, aSig, 0, status);
159 /*----------------------------------------------------------------------------
160 | Returns the exponent of the extended double-precision floating-point
161 | value `a' as an extended double-precision value.
162 *----------------------------------------------------------------------------*/
164 floatx80 floatx80_getexp(floatx80 a, float_status *status)
166 flag aSign;
167 int32_t aExp;
168 uint64_t aSig;
170 aSig = extractFloatx80Frac(a);
171 aExp = extractFloatx80Exp(a);
172 aSign = extractFloatx80Sign(a);
174 if (aExp == 0x7FFF) {
175 if ((uint64_t) (aSig << 1)) {
176 return propagateFloatx80NaNOneArg(a , status);
178 float_raise(float_flag_invalid , status);
179 return floatx80_default_nan(status);
182 if (aExp == 0) {
183 if (aSig == 0) {
184 return packFloatx80(aSign, 0, 0);
186 normalizeFloatx80Subnormal(aSig, &aExp, &aSig);
189 return int32_to_floatx80(aExp - 0x3FFF, status);
192 /*----------------------------------------------------------------------------
193 | Scales extended double-precision floating-point value in operand `a' by
194 | value `b'. The function truncates the value in the second operand 'b' to
195 | an integral value and adds that value to the exponent of the operand 'a'.
196 | The operation performed according to the IEC/IEEE Standard for Binary
197 | Floating-Point Arithmetic.
198 *----------------------------------------------------------------------------*/
200 floatx80 floatx80_scale(floatx80 a, floatx80 b, float_status *status)
202 flag aSign, bSign;
203 int32_t aExp, bExp, shiftCount;
204 uint64_t aSig, bSig;
206 aSig = extractFloatx80Frac(a);
207 aExp = extractFloatx80Exp(a);
208 aSign = extractFloatx80Sign(a);
209 bSig = extractFloatx80Frac(b);
210 bExp = extractFloatx80Exp(b);
211 bSign = extractFloatx80Sign(b);
213 if (bExp == 0x7FFF) {
214 if ((uint64_t) (bSig << 1) ||
215 ((aExp == 0x7FFF) && (uint64_t) (aSig << 1))) {
216 return propagateFloatx80NaN(a, b, status);
218 float_raise(float_flag_invalid , status);
219 return floatx80_default_nan(status);
221 if (aExp == 0x7FFF) {
222 if ((uint64_t) (aSig << 1)) {
223 return propagateFloatx80NaN(a, b, status);
225 return packFloatx80(aSign, floatx80_infinity.high,
226 floatx80_infinity.low);
228 if (aExp == 0) {
229 if (aSig == 0) {
230 return packFloatx80(aSign, 0, 0);
232 if (bExp < 0x3FFF) {
233 return a;
235 normalizeFloatx80Subnormal(aSig, &aExp, &aSig);
238 if (bExp < 0x3FFF) {
239 return a;
242 if (0x400F < bExp) {
243 aExp = bSign ? -0x6001 : 0xE000;
244 return roundAndPackFloatx80(status->floatx80_rounding_precision,
245 aSign, aExp, aSig, 0, status);
248 shiftCount = 0x403E - bExp;
249 bSig >>= shiftCount;
250 aExp = bSign ? (aExp - bSig) : (aExp + bSig);
252 return roundAndPackFloatx80(status->floatx80_rounding_precision,
253 aSign, aExp, aSig, 0, status);
256 floatx80 floatx80_move(floatx80 a, float_status *status)
258 flag aSign;
259 int32_t aExp;
260 uint64_t aSig;
262 aSig = extractFloatx80Frac(a);
263 aExp = extractFloatx80Exp(a);
264 aSign = extractFloatx80Sign(a);
266 if (aExp == 0x7FFF) {
267 if ((uint64_t)(aSig << 1)) {
268 return propagateFloatx80NaNOneArg(a, status);
270 return a;
272 if (aExp == 0) {
273 if (aSig == 0) {
274 return a;
276 normalizeRoundAndPackFloatx80(status->floatx80_rounding_precision,
277 aSign, aExp, aSig, 0, status);
279 return roundAndPackFloatx80(status->floatx80_rounding_precision, aSign,
280 aExp, aSig, 0, status);
283 /*----------------------------------------------------------------------------
284 | Algorithms for transcendental functions supported by MC68881 and MC68882
285 | mathematical coprocessors. The functions are derived from FPSP library.
286 *----------------------------------------------------------------------------*/
288 #define one_exp 0x3FFF
289 #define one_sig LIT64(0x8000000000000000)
291 /*----------------------------------------------------------------------------
292 | Function for compactifying extended double-precision floating point values.
293 *----------------------------------------------------------------------------*/
295 static int32_t floatx80_make_compact(int32_t aExp, uint64_t aSig)
297 return (aExp << 16) | (aSig >> 48);
300 /*----------------------------------------------------------------------------
301 | Log base e of x plus 1
302 *----------------------------------------------------------------------------*/
304 floatx80 floatx80_lognp1(floatx80 a, float_status *status)
306 flag aSign;
307 int32_t aExp;
308 uint64_t aSig, fSig;
310 int8_t user_rnd_mode, user_rnd_prec;
312 int32_t compact, j, k;
313 floatx80 fp0, fp1, fp2, fp3, f, logof2, klog2, saveu;
315 aSig = extractFloatx80Frac(a);
316 aExp = extractFloatx80Exp(a);
317 aSign = extractFloatx80Sign(a);
319 if (aExp == 0x7FFF) {
320 if ((uint64_t) (aSig << 1)) {
321 propagateFloatx80NaNOneArg(a, status);
323 if (aSign) {
324 float_raise(float_flag_invalid, status);
325 return floatx80_default_nan(status);
327 return packFloatx80(0, floatx80_infinity.high, floatx80_infinity.low);
330 if (aExp == 0 && aSig == 0) {
331 return packFloatx80(aSign, 0, 0);
334 if (aSign && aExp >= one_exp) {
335 if (aExp == one_exp && aSig == one_sig) {
336 float_raise(float_flag_divbyzero, status);
337 packFloatx80(aSign, floatx80_infinity.high, floatx80_infinity.low);
339 float_raise(float_flag_invalid, status);
340 return floatx80_default_nan(status);
343 if (aExp < 0x3f99 || (aExp == 0x3f99 && aSig == one_sig)) {
344 /* <= min threshold */
345 float_raise(float_flag_inexact, status);
346 return floatx80_move(a, status);
349 user_rnd_mode = status->float_rounding_mode;
350 user_rnd_prec = status->floatx80_rounding_precision;
351 status->float_rounding_mode = float_round_nearest_even;
352 status->floatx80_rounding_precision = 80;
354 compact = floatx80_make_compact(aExp, aSig);
356 fp0 = a; /* Z */
357 fp1 = a;
359 fp0 = floatx80_add(fp0, float32_to_floatx80(make_float32(0x3F800000),
360 status), status); /* X = (1+Z) */
362 aExp = extractFloatx80Exp(fp0);
363 aSig = extractFloatx80Frac(fp0);
365 compact = floatx80_make_compact(aExp, aSig);
367 if (compact < 0x3FFE8000 || compact > 0x3FFFC000) {
368 /* |X| < 1/2 or |X| > 3/2 */
369 k = aExp - 0x3FFF;
370 fp1 = int32_to_floatx80(k, status);
372 fSig = (aSig & LIT64(0xFE00000000000000)) | LIT64(0x0100000000000000);
373 j = (fSig >> 56) & 0x7E; /* DISPLACEMENT FOR 1/F */
375 f = packFloatx80(0, 0x3FFF, fSig); /* F */
376 fp0 = packFloatx80(0, 0x3FFF, aSig); /* Y */
378 fp0 = floatx80_sub(fp0, f, status); /* Y-F */
380 lp1cont1:
381 /* LP1CONT1 */
382 fp0 = floatx80_mul(fp0, log_tbl[j], status); /* FP0 IS U = (Y-F)/F */
383 logof2 = packFloatx80(0, 0x3FFE, LIT64(0xB17217F7D1CF79AC));
384 klog2 = floatx80_mul(fp1, logof2, status); /* FP1 IS K*LOG2 */
385 fp2 = floatx80_mul(fp0, fp0, status); /* FP2 IS V=U*U */
387 fp3 = fp2;
388 fp1 = fp2;
390 fp1 = floatx80_mul(fp1, float64_to_floatx80(
391 make_float64(0x3FC2499AB5E4040B), status),
392 status); /* V*A6 */
393 fp2 = floatx80_mul(fp2, float64_to_floatx80(
394 make_float64(0xBFC555B5848CB7DB), status),
395 status); /* V*A5 */
396 fp1 = floatx80_add(fp1, float64_to_floatx80(
397 make_float64(0x3FC99999987D8730), status),
398 status); /* A4+V*A6 */
399 fp2 = floatx80_add(fp2, float64_to_floatx80(
400 make_float64(0xBFCFFFFFFF6F7E97), status),
401 status); /* A3+V*A5 */
402 fp1 = floatx80_mul(fp1, fp3, status); /* V*(A4+V*A6) */
403 fp2 = floatx80_mul(fp2, fp3, status); /* V*(A3+V*A5) */
404 fp1 = floatx80_add(fp1, float64_to_floatx80(
405 make_float64(0x3FD55555555555A4), status),
406 status); /* A2+V*(A4+V*A6) */
407 fp2 = floatx80_add(fp2, float64_to_floatx80(
408 make_float64(0xBFE0000000000008), status),
409 status); /* A1+V*(A3+V*A5) */
410 fp1 = floatx80_mul(fp1, fp3, status); /* V*(A2+V*(A4+V*A6)) */
411 fp2 = floatx80_mul(fp2, fp3, status); /* V*(A1+V*(A3+V*A5)) */
412 fp1 = floatx80_mul(fp1, fp0, status); /* U*V*(A2+V*(A4+V*A6)) */
413 fp0 = floatx80_add(fp0, fp2, status); /* U+V*(A1+V*(A3+V*A5)) */
415 fp1 = floatx80_add(fp1, log_tbl[j + 1],
416 status); /* LOG(F)+U*V*(A2+V*(A4+V*A6)) */
417 fp0 = floatx80_add(fp0, fp1, status); /* FP0 IS LOG(F) + LOG(1+U) */
419 status->float_rounding_mode = user_rnd_mode;
420 status->floatx80_rounding_precision = user_rnd_prec;
422 a = floatx80_add(fp0, klog2, status);
424 float_raise(float_flag_inexact, status);
426 return a;
427 } else if (compact < 0x3FFEF07D || compact > 0x3FFF8841) {
428 /* |X| < 1/16 or |X| > -1/16 */
429 /* LP1CARE */
430 fSig = (aSig & LIT64(0xFE00000000000000)) | LIT64(0x0100000000000000);
431 f = packFloatx80(0, 0x3FFF, fSig); /* F */
432 j = (fSig >> 56) & 0x7E; /* DISPLACEMENT FOR 1/F */
434 if (compact >= 0x3FFF8000) { /* 1+Z >= 1 */
435 /* KISZERO */
436 fp0 = floatx80_sub(float32_to_floatx80(make_float32(0x3F800000),
437 status), f, status); /* 1-F */
438 fp0 = floatx80_add(fp0, fp1, status); /* FP0 IS Y-F = (1-F)+Z */
439 fp1 = packFloatx80(0, 0, 0); /* K = 0 */
440 } else {
441 /* KISNEG */
442 fp0 = floatx80_sub(float32_to_floatx80(make_float32(0x40000000),
443 status), f, status); /* 2-F */
444 fp1 = floatx80_add(fp1, fp1, status); /* 2Z */
445 fp0 = floatx80_add(fp0, fp1, status); /* FP0 IS Y-F = (2-F)+2Z */
446 fp1 = packFloatx80(1, one_exp, one_sig); /* K = -1 */
448 goto lp1cont1;
449 } else {
450 /* LP1ONE16 */
451 fp1 = floatx80_add(fp1, fp1, status); /* FP1 IS 2Z */
452 fp0 = floatx80_add(fp0, float32_to_floatx80(make_float32(0x3F800000),
453 status), status); /* FP0 IS 1+X */
455 /* LP1CONT2 */
456 fp1 = floatx80_div(fp1, fp0, status); /* U */
457 saveu = fp1;
458 fp0 = floatx80_mul(fp1, fp1, status); /* FP0 IS V = U*U */
459 fp1 = floatx80_mul(fp0, fp0, status); /* FP1 IS W = V*V */
461 fp3 = float64_to_floatx80(make_float64(0x3F175496ADD7DAD6),
462 status); /* B5 */
463 fp2 = float64_to_floatx80(make_float64(0x3F3C71C2FE80C7E0),
464 status); /* B4 */
465 fp3 = floatx80_mul(fp3, fp1, status); /* W*B5 */
466 fp2 = floatx80_mul(fp2, fp1, status); /* W*B4 */
467 fp3 = floatx80_add(fp3, float64_to_floatx80(
468 make_float64(0x3F624924928BCCFF), status),
469 status); /* B3+W*B5 */
470 fp2 = floatx80_add(fp2, float64_to_floatx80(
471 make_float64(0x3F899999999995EC), status),
472 status); /* B2+W*B4 */
473 fp1 = floatx80_mul(fp1, fp3, status); /* W*(B3+W*B5) */
474 fp2 = floatx80_mul(fp2, fp0, status); /* V*(B2+W*B4) */
475 fp1 = floatx80_add(fp1, float64_to_floatx80(
476 make_float64(0x3FB5555555555555), status),
477 status); /* B1+W*(B3+W*B5) */
479 fp0 = floatx80_mul(fp0, saveu, status); /* FP0 IS U*V */
480 fp1 = floatx80_add(fp1, fp2,
481 status); /* B1+W*(B3+W*B5) + V*(B2+W*B4) */
482 fp0 = floatx80_mul(fp0, fp1,
483 status); /* U*V*([B1+W*(B3+W*B5)] + [V*(B2+W*B4)]) */
485 status->float_rounding_mode = user_rnd_mode;
486 status->floatx80_rounding_precision = user_rnd_prec;
488 a = floatx80_add(fp0, saveu, status);
490 /*if (!floatx80_is_zero(a)) { */
491 float_raise(float_flag_inexact, status);
492 /*} */
494 return a;
498 /*----------------------------------------------------------------------------
499 | Log base e
500 *----------------------------------------------------------------------------*/
502 floatx80 floatx80_logn(floatx80 a, float_status *status)
504 flag aSign;
505 int32_t aExp;
506 uint64_t aSig, fSig;
508 int8_t user_rnd_mode, user_rnd_prec;
510 int32_t compact, j, k, adjk;
511 floatx80 fp0, fp1, fp2, fp3, f, logof2, klog2, saveu;
513 aSig = extractFloatx80Frac(a);
514 aExp = extractFloatx80Exp(a);
515 aSign = extractFloatx80Sign(a);
517 if (aExp == 0x7FFF) {
518 if ((uint64_t) (aSig << 1)) {
519 propagateFloatx80NaNOneArg(a, status);
521 if (aSign == 0) {
522 return packFloatx80(0, floatx80_infinity.high,
523 floatx80_infinity.low);
527 adjk = 0;
529 if (aExp == 0) {
530 if (aSig == 0) { /* zero */
531 float_raise(float_flag_divbyzero, status);
532 return packFloatx80(1, floatx80_infinity.high,
533 floatx80_infinity.low);
535 if ((aSig & one_sig) == 0) { /* denormal */
536 normalizeFloatx80Subnormal(aSig, &aExp, &aSig);
537 adjk = -100;
538 aExp += 100;
539 a = packFloatx80(aSign, aExp, aSig);
543 if (aSign) {
544 float_raise(float_flag_invalid, status);
545 return floatx80_default_nan(status);
548 user_rnd_mode = status->float_rounding_mode;
549 user_rnd_prec = status->floatx80_rounding_precision;
550 status->float_rounding_mode = float_round_nearest_even;
551 status->floatx80_rounding_precision = 80;
553 compact = floatx80_make_compact(aExp, aSig);
555 if (compact < 0x3FFEF07D || compact > 0x3FFF8841) {
556 /* |X| < 15/16 or |X| > 17/16 */
557 k = aExp - 0x3FFF;
558 k += adjk;
559 fp1 = int32_to_floatx80(k, status);
561 fSig = (aSig & LIT64(0xFE00000000000000)) | LIT64(0x0100000000000000);
562 j = (fSig >> 56) & 0x7E; /* DISPLACEMENT FOR 1/F */
564 f = packFloatx80(0, 0x3FFF, fSig); /* F */
565 fp0 = packFloatx80(0, 0x3FFF, aSig); /* Y */
567 fp0 = floatx80_sub(fp0, f, status); /* Y-F */
569 /* LP1CONT1 */
570 fp0 = floatx80_mul(fp0, log_tbl[j], status); /* FP0 IS U = (Y-F)/F */
571 logof2 = packFloatx80(0, 0x3FFE, LIT64(0xB17217F7D1CF79AC));
572 klog2 = floatx80_mul(fp1, logof2, status); /* FP1 IS K*LOG2 */
573 fp2 = floatx80_mul(fp0, fp0, status); /* FP2 IS V=U*U */
575 fp3 = fp2;
576 fp1 = fp2;
578 fp1 = floatx80_mul(fp1, float64_to_floatx80(
579 make_float64(0x3FC2499AB5E4040B), status),
580 status); /* V*A6 */
581 fp2 = floatx80_mul(fp2, float64_to_floatx80(
582 make_float64(0xBFC555B5848CB7DB), status),
583 status); /* V*A5 */
584 fp1 = floatx80_add(fp1, float64_to_floatx80(
585 make_float64(0x3FC99999987D8730), status),
586 status); /* A4+V*A6 */
587 fp2 = floatx80_add(fp2, float64_to_floatx80(
588 make_float64(0xBFCFFFFFFF6F7E97), status),
589 status); /* A3+V*A5 */
590 fp1 = floatx80_mul(fp1, fp3, status); /* V*(A4+V*A6) */
591 fp2 = floatx80_mul(fp2, fp3, status); /* V*(A3+V*A5) */
592 fp1 = floatx80_add(fp1, float64_to_floatx80(
593 make_float64(0x3FD55555555555A4), status),
594 status); /* A2+V*(A4+V*A6) */
595 fp2 = floatx80_add(fp2, float64_to_floatx80(
596 make_float64(0xBFE0000000000008), status),
597 status); /* A1+V*(A3+V*A5) */
598 fp1 = floatx80_mul(fp1, fp3, status); /* V*(A2+V*(A4+V*A6)) */
599 fp2 = floatx80_mul(fp2, fp3, status); /* V*(A1+V*(A3+V*A5)) */
600 fp1 = floatx80_mul(fp1, fp0, status); /* U*V*(A2+V*(A4+V*A6)) */
601 fp0 = floatx80_add(fp0, fp2, status); /* U+V*(A1+V*(A3+V*A5)) */
603 fp1 = floatx80_add(fp1, log_tbl[j + 1],
604 status); /* LOG(F)+U*V*(A2+V*(A4+V*A6)) */
605 fp0 = floatx80_add(fp0, fp1, status); /* FP0 IS LOG(F) + LOG(1+U) */
607 status->float_rounding_mode = user_rnd_mode;
608 status->floatx80_rounding_precision = user_rnd_prec;
610 a = floatx80_add(fp0, klog2, status);
612 float_raise(float_flag_inexact, status);
614 return a;
615 } else { /* |X-1| >= 1/16 */
616 fp0 = a;
617 fp1 = a;
618 fp1 = floatx80_sub(fp1, float32_to_floatx80(make_float32(0x3F800000),
619 status), status); /* FP1 IS X-1 */
620 fp0 = floatx80_add(fp0, float32_to_floatx80(make_float32(0x3F800000),
621 status), status); /* FP0 IS X+1 */
622 fp1 = floatx80_add(fp1, fp1, status); /* FP1 IS 2(X-1) */
624 /* LP1CONT2 */
625 fp1 = floatx80_div(fp1, fp0, status); /* U */
626 saveu = fp1;
627 fp0 = floatx80_mul(fp1, fp1, status); /* FP0 IS V = U*U */
628 fp1 = floatx80_mul(fp0, fp0, status); /* FP1 IS W = V*V */
630 fp3 = float64_to_floatx80(make_float64(0x3F175496ADD7DAD6),
631 status); /* B5 */
632 fp2 = float64_to_floatx80(make_float64(0x3F3C71C2FE80C7E0),
633 status); /* B4 */
634 fp3 = floatx80_mul(fp3, fp1, status); /* W*B5 */
635 fp2 = floatx80_mul(fp2, fp1, status); /* W*B4 */
636 fp3 = floatx80_add(fp3, float64_to_floatx80(
637 make_float64(0x3F624924928BCCFF), status),
638 status); /* B3+W*B5 */
639 fp2 = floatx80_add(fp2, float64_to_floatx80(
640 make_float64(0x3F899999999995EC), status),
641 status); /* B2+W*B4 */
642 fp1 = floatx80_mul(fp1, fp3, status); /* W*(B3+W*B5) */
643 fp2 = floatx80_mul(fp2, fp0, status); /* V*(B2+W*B4) */
644 fp1 = floatx80_add(fp1, float64_to_floatx80(
645 make_float64(0x3FB5555555555555), status),
646 status); /* B1+W*(B3+W*B5) */
648 fp0 = floatx80_mul(fp0, saveu, status); /* FP0 IS U*V */
649 fp1 = floatx80_add(fp1, fp2, status); /* B1+W*(B3+W*B5) + V*(B2+W*B4) */
650 fp0 = floatx80_mul(fp0, fp1,
651 status); /* U*V*([B1+W*(B3+W*B5)] + [V*(B2+W*B4)]) */
653 status->float_rounding_mode = user_rnd_mode;
654 status->floatx80_rounding_precision = user_rnd_prec;
656 a = floatx80_add(fp0, saveu, status);
658 /*if (!floatx80_is_zero(a)) { */
659 float_raise(float_flag_inexact, status);
660 /*} */
662 return a;
666 /*----------------------------------------------------------------------------
667 | Log base 10
668 *----------------------------------------------------------------------------*/
670 floatx80 floatx80_log10(floatx80 a, float_status *status)
672 flag aSign;
673 int32_t aExp;
674 uint64_t aSig;
676 int8_t user_rnd_mode, user_rnd_prec;
678 floatx80 fp0, fp1;
680 aSig = extractFloatx80Frac(a);
681 aExp = extractFloatx80Exp(a);
682 aSign = extractFloatx80Sign(a);
684 if (aExp == 0x7FFF) {
685 if ((uint64_t) (aSig << 1)) {
686 propagateFloatx80NaNOneArg(a, status);
688 if (aSign == 0) {
689 return packFloatx80(0, floatx80_infinity.high,
690 floatx80_infinity.low);
694 if (aExp == 0 && aSig == 0) {
695 float_raise(float_flag_divbyzero, status);
696 return packFloatx80(1, floatx80_infinity.high,
697 floatx80_infinity.low);
700 if (aSign) {
701 float_raise(float_flag_invalid, status);
702 return floatx80_default_nan(status);
705 user_rnd_mode = status->float_rounding_mode;
706 user_rnd_prec = status->floatx80_rounding_precision;
707 status->float_rounding_mode = float_round_nearest_even;
708 status->floatx80_rounding_precision = 80;
710 fp0 = floatx80_logn(a, status);
711 fp1 = packFloatx80(0, 0x3FFD, LIT64(0xDE5BD8A937287195)); /* INV_L10 */
713 status->float_rounding_mode = user_rnd_mode;
714 status->floatx80_rounding_precision = user_rnd_prec;
716 a = floatx80_mul(fp0, fp1, status); /* LOGN(X)*INV_L10 */
718 float_raise(float_flag_inexact, status);
720 return a;
723 /*----------------------------------------------------------------------------
724 | Log base 2
725 *----------------------------------------------------------------------------*/
727 floatx80 floatx80_log2(floatx80 a, float_status *status)
729 flag aSign;
730 int32_t aExp;
731 uint64_t aSig;
733 int8_t user_rnd_mode, user_rnd_prec;
735 floatx80 fp0, fp1;
737 aSig = extractFloatx80Frac(a);
738 aExp = extractFloatx80Exp(a);
739 aSign = extractFloatx80Sign(a);
741 if (aExp == 0x7FFF) {
742 if ((uint64_t) (aSig << 1)) {
743 propagateFloatx80NaNOneArg(a, status);
745 if (aSign == 0) {
746 return packFloatx80(0, floatx80_infinity.high,
747 floatx80_infinity.low);
751 if (aExp == 0) {
752 if (aSig == 0) {
753 float_raise(float_flag_divbyzero, status);
754 return packFloatx80(1, floatx80_infinity.high,
755 floatx80_infinity.low);
757 normalizeFloatx80Subnormal(aSig, &aExp, &aSig);
760 if (aSign) {
761 float_raise(float_flag_invalid, status);
762 return floatx80_default_nan(status);
765 user_rnd_mode = status->float_rounding_mode;
766 user_rnd_prec = status->floatx80_rounding_precision;
767 status->float_rounding_mode = float_round_nearest_even;
768 status->floatx80_rounding_precision = 80;
770 if (aSig == one_sig) { /* X is 2^k */
771 status->float_rounding_mode = user_rnd_mode;
772 status->floatx80_rounding_precision = user_rnd_prec;
774 a = int32_to_floatx80(aExp - 0x3FFF, status);
775 } else {
776 fp0 = floatx80_logn(a, status);
777 fp1 = packFloatx80(0, 0x3FFF, LIT64(0xB8AA3B295C17F0BC)); /* INV_L2 */
779 status->float_rounding_mode = user_rnd_mode;
780 status->floatx80_rounding_precision = user_rnd_prec;
782 a = floatx80_mul(fp0, fp1, status); /* LOGN(X)*INV_L2 */
785 float_raise(float_flag_inexact, status);
787 return a;
790 /*----------------------------------------------------------------------------
791 | e to x
792 *----------------------------------------------------------------------------*/
794 floatx80 floatx80_etox(floatx80 a, float_status *status)
796 flag aSign;
797 int32_t aExp;
798 uint64_t aSig;
800 int8_t user_rnd_mode, user_rnd_prec;
802 int32_t compact, n, j, k, m, m1;
803 floatx80 fp0, fp1, fp2, fp3, l2, scale, adjscale;
804 flag adjflag;
806 aSig = extractFloatx80Frac(a);
807 aExp = extractFloatx80Exp(a);
808 aSign = extractFloatx80Sign(a);
810 if (aExp == 0x7FFF) {
811 if ((uint64_t) (aSig << 1)) {
812 return propagateFloatx80NaNOneArg(a, status);
814 if (aSign) {
815 return packFloatx80(0, 0, 0);
817 return packFloatx80(0, floatx80_infinity.high,
818 floatx80_infinity.low);
821 if (aExp == 0 && aSig == 0) {
822 return packFloatx80(0, one_exp, one_sig);
825 user_rnd_mode = status->float_rounding_mode;
826 user_rnd_prec = status->floatx80_rounding_precision;
827 status->float_rounding_mode = float_round_nearest_even;
828 status->floatx80_rounding_precision = 80;
830 adjflag = 0;
832 if (aExp >= 0x3FBE) { /* |X| >= 2^(-65) */
833 compact = floatx80_make_compact(aExp, aSig);
835 if (compact < 0x400CB167) { /* |X| < 16380 log2 */
836 fp0 = a;
837 fp1 = a;
838 fp0 = floatx80_mul(fp0, float32_to_floatx80(
839 make_float32(0x42B8AA3B), status),
840 status); /* 64/log2 * X */
841 adjflag = 0;
842 n = floatx80_to_int32(fp0, status); /* int(64/log2*X) */
843 fp0 = int32_to_floatx80(n, status);
845 j = n & 0x3F; /* J = N mod 64 */
846 m = n / 64; /* NOTE: this is really arithmetic right shift by 6 */
847 if (n < 0 && j) {
848 /* arithmetic right shift is division and
849 * round towards minus infinity
851 m--;
853 m += 0x3FFF; /* biased exponent of 2^(M) */
855 expcont1:
856 fp2 = fp0; /* N */
857 fp0 = floatx80_mul(fp0, float32_to_floatx80(
858 make_float32(0xBC317218), status),
859 status); /* N * L1, L1 = lead(-log2/64) */
860 l2 = packFloatx80(0, 0x3FDC, LIT64(0x82E308654361C4C6));
861 fp2 = floatx80_mul(fp2, l2, status); /* N * L2, L1+L2 = -log2/64 */
862 fp0 = floatx80_add(fp0, fp1, status); /* X + N*L1 */
863 fp0 = floatx80_add(fp0, fp2, status); /* R */
865 fp1 = floatx80_mul(fp0, fp0, status); /* S = R*R */
866 fp2 = float32_to_floatx80(make_float32(0x3AB60B70),
867 status); /* A5 */
868 fp2 = floatx80_mul(fp2, fp1, status); /* fp2 is S*A5 */
869 fp3 = floatx80_mul(float32_to_floatx80(make_float32(0x3C088895),
870 status), fp1,
871 status); /* fp3 is S*A4 */
872 fp2 = floatx80_add(fp2, float64_to_floatx80(make_float64(
873 0x3FA5555555554431), status),
874 status); /* fp2 is A3+S*A5 */
875 fp3 = floatx80_add(fp3, float64_to_floatx80(make_float64(
876 0x3FC5555555554018), status),
877 status); /* fp3 is A2+S*A4 */
878 fp2 = floatx80_mul(fp2, fp1, status); /* fp2 is S*(A3+S*A5) */
879 fp3 = floatx80_mul(fp3, fp1, status); /* fp3 is S*(A2+S*A4) */
880 fp2 = floatx80_add(fp2, float32_to_floatx80(
881 make_float32(0x3F000000), status),
882 status); /* fp2 is A1+S*(A3+S*A5) */
883 fp3 = floatx80_mul(fp3, fp0, status); /* fp3 IS R*S*(A2+S*A4) */
884 fp2 = floatx80_mul(fp2, fp1,
885 status); /* fp2 IS S*(A1+S*(A3+S*A5)) */
886 fp0 = floatx80_add(fp0, fp3, status); /* fp0 IS R+R*S*(A2+S*A4) */
887 fp0 = floatx80_add(fp0, fp2, status); /* fp0 IS EXP(R) - 1 */
889 fp1 = exp_tbl[j];
890 fp0 = floatx80_mul(fp0, fp1, status); /* 2^(J/64)*(Exp(R)-1) */
891 fp0 = floatx80_add(fp0, float32_to_floatx80(exp_tbl2[j], status),
892 status); /* accurate 2^(J/64) */
893 fp0 = floatx80_add(fp0, fp1,
894 status); /* 2^(J/64) + 2^(J/64)*(Exp(R)-1) */
896 scale = packFloatx80(0, m, one_sig);
897 if (adjflag) {
898 adjscale = packFloatx80(0, m1, one_sig);
899 fp0 = floatx80_mul(fp0, adjscale, status);
902 status->float_rounding_mode = user_rnd_mode;
903 status->floatx80_rounding_precision = user_rnd_prec;
905 a = floatx80_mul(fp0, scale, status);
907 float_raise(float_flag_inexact, status);
909 return a;
910 } else { /* |X| >= 16380 log2 */
911 if (compact > 0x400CB27C) { /* |X| >= 16480 log2 */
912 status->float_rounding_mode = user_rnd_mode;
913 status->floatx80_rounding_precision = user_rnd_prec;
914 if (aSign) {
915 a = roundAndPackFloatx80(
916 status->floatx80_rounding_precision,
917 0, -0x1000, aSig, 0, status);
918 } else {
919 a = roundAndPackFloatx80(
920 status->floatx80_rounding_precision,
921 0, 0x8000, aSig, 0, status);
923 float_raise(float_flag_inexact, status);
925 return a;
926 } else {
927 fp0 = a;
928 fp1 = a;
929 fp0 = floatx80_mul(fp0, float32_to_floatx80(
930 make_float32(0x42B8AA3B), status),
931 status); /* 64/log2 * X */
932 adjflag = 1;
933 n = floatx80_to_int32(fp0, status); /* int(64/log2*X) */
934 fp0 = int32_to_floatx80(n, status);
936 j = n & 0x3F; /* J = N mod 64 */
937 /* NOTE: this is really arithmetic right shift by 6 */
938 k = n / 64;
939 if (n < 0 && j) {
940 /* arithmetic right shift is division and
941 * round towards minus infinity
943 k--;
945 /* NOTE: this is really arithmetic right shift by 1 */
946 m1 = k / 2;
947 if (k < 0 && (k & 1)) {
948 /* arithmetic right shift is division and
949 * round towards minus infinity
951 m1--;
953 m = k - m1;
954 m1 += 0x3FFF; /* biased exponent of 2^(M1) */
955 m += 0x3FFF; /* biased exponent of 2^(M) */
957 goto expcont1;
960 } else { /* |X| < 2^(-65) */
961 status->float_rounding_mode = user_rnd_mode;
962 status->floatx80_rounding_precision = user_rnd_prec;
964 a = floatx80_add(a, float32_to_floatx80(make_float32(0x3F800000),
965 status), status); /* 1 + X */
967 float_raise(float_flag_inexact, status);
969 return a;
973 /*----------------------------------------------------------------------------
974 | 2 to x
975 *----------------------------------------------------------------------------*/
977 floatx80 floatx80_twotox(floatx80 a, float_status *status)
979 flag aSign;
980 int32_t aExp;
981 uint64_t aSig;
983 int8_t user_rnd_mode, user_rnd_prec;
985 int32_t compact, n, j, l, m, m1;
986 floatx80 fp0, fp1, fp2, fp3, adjfact, fact1, fact2;
988 aSig = extractFloatx80Frac(a);
989 aExp = extractFloatx80Exp(a);
990 aSign = extractFloatx80Sign(a);
992 if (aExp == 0x7FFF) {
993 if ((uint64_t) (aSig << 1)) {
994 return propagateFloatx80NaNOneArg(a, status);
996 if (aSign) {
997 return packFloatx80(0, 0, 0);
999 return packFloatx80(0, floatx80_infinity.high,
1000 floatx80_infinity.low);
1003 if (aExp == 0 && aSig == 0) {
1004 return packFloatx80(0, one_exp, one_sig);
1007 user_rnd_mode = status->float_rounding_mode;
1008 user_rnd_prec = status->floatx80_rounding_precision;
1009 status->float_rounding_mode = float_round_nearest_even;
1010 status->floatx80_rounding_precision = 80;
1012 fp0 = a;
1014 compact = floatx80_make_compact(aExp, aSig);
1016 if (compact < 0x3FB98000 || compact > 0x400D80C0) {
1017 /* |X| > 16480 or |X| < 2^(-70) */
1018 if (compact > 0x3FFF8000) { /* |X| > 16480 */
1019 status->float_rounding_mode = user_rnd_mode;
1020 status->floatx80_rounding_precision = user_rnd_prec;
1022 if (aSign) {
1023 return roundAndPackFloatx80(status->floatx80_rounding_precision,
1024 0, -0x1000, aSig, 0, status);
1025 } else {
1026 return roundAndPackFloatx80(status->floatx80_rounding_precision,
1027 0, 0x8000, aSig, 0, status);
1029 } else { /* |X| < 2^(-70) */
1030 status->float_rounding_mode = user_rnd_mode;
1031 status->floatx80_rounding_precision = user_rnd_prec;
1033 a = floatx80_add(fp0, float32_to_floatx80(
1034 make_float32(0x3F800000), status),
1035 status); /* 1 + X */
1037 float_raise(float_flag_inexact, status);
1039 return a;
1041 } else { /* 2^(-70) <= |X| <= 16480 */
1042 fp1 = fp0; /* X */
1043 fp1 = floatx80_mul(fp1, float32_to_floatx80(
1044 make_float32(0x42800000), status),
1045 status); /* X * 64 */
1046 n = floatx80_to_int32(fp1, status);
1047 fp1 = int32_to_floatx80(n, status);
1048 j = n & 0x3F;
1049 l = n / 64; /* NOTE: this is really arithmetic right shift by 6 */
1050 if (n < 0 && j) {
1051 /* arithmetic right shift is division and
1052 * round towards minus infinity
1054 l--;
1056 m = l / 2; /* NOTE: this is really arithmetic right shift by 1 */
1057 if (l < 0 && (l & 1)) {
1058 /* arithmetic right shift is division and
1059 * round towards minus infinity
1061 m--;
1063 m1 = l - m;
1064 m1 += 0x3FFF; /* ADJFACT IS 2^(M') */
1066 adjfact = packFloatx80(0, m1, one_sig);
1067 fact1 = exp2_tbl[j];
1068 fact1.high += m;
1069 fact2.high = exp2_tbl2[j] >> 16;
1070 fact2.high += m;
1071 fact2.low = (uint64_t)(exp2_tbl2[j] & 0xFFFF);
1072 fact2.low <<= 48;
1074 fp1 = floatx80_mul(fp1, float32_to_floatx80(
1075 make_float32(0x3C800000), status),
1076 status); /* (1/64)*N */
1077 fp0 = floatx80_sub(fp0, fp1, status); /* X - (1/64)*INT(64 X) */
1078 fp2 = packFloatx80(0, 0x3FFE, LIT64(0xB17217F7D1CF79AC)); /* LOG2 */
1079 fp0 = floatx80_mul(fp0, fp2, status); /* R */
1081 /* EXPR */
1082 fp1 = floatx80_mul(fp0, fp0, status); /* S = R*R */
1083 fp2 = float64_to_floatx80(make_float64(0x3F56C16D6F7BD0B2),
1084 status); /* A5 */
1085 fp3 = float64_to_floatx80(make_float64(0x3F811112302C712C),
1086 status); /* A4 */
1087 fp2 = floatx80_mul(fp2, fp1, status); /* S*A5 */
1088 fp3 = floatx80_mul(fp3, fp1, status); /* S*A4 */
1089 fp2 = floatx80_add(fp2, float64_to_floatx80(
1090 make_float64(0x3FA5555555554CC1), status),
1091 status); /* A3+S*A5 */
1092 fp3 = floatx80_add(fp3, float64_to_floatx80(
1093 make_float64(0x3FC5555555554A54), status),
1094 status); /* A2+S*A4 */
1095 fp2 = floatx80_mul(fp2, fp1, status); /* S*(A3+S*A5) */
1096 fp3 = floatx80_mul(fp3, fp1, status); /* S*(A2+S*A4) */
1097 fp2 = floatx80_add(fp2, float64_to_floatx80(
1098 make_float64(0x3FE0000000000000), status),
1099 status); /* A1+S*(A3+S*A5) */
1100 fp3 = floatx80_mul(fp3, fp0, status); /* R*S*(A2+S*A4) */
1102 fp2 = floatx80_mul(fp2, fp1, status); /* S*(A1+S*(A3+S*A5)) */
1103 fp0 = floatx80_add(fp0, fp3, status); /* R+R*S*(A2+S*A4) */
1104 fp0 = floatx80_add(fp0, fp2, status); /* EXP(R) - 1 */
1106 fp0 = floatx80_mul(fp0, fact1, status);
1107 fp0 = floatx80_add(fp0, fact2, status);
1108 fp0 = floatx80_add(fp0, fact1, status);
1110 status->float_rounding_mode = user_rnd_mode;
1111 status->floatx80_rounding_precision = user_rnd_prec;
1113 a = floatx80_mul(fp0, adjfact, status);
1115 float_raise(float_flag_inexact, status);
1117 return a;
1121 /*----------------------------------------------------------------------------
1122 | 10 to x
1123 *----------------------------------------------------------------------------*/
1125 floatx80 floatx80_tentox(floatx80 a, float_status *status)
1127 flag aSign;
1128 int32_t aExp;
1129 uint64_t aSig;
1131 int8_t user_rnd_mode, user_rnd_prec;
1133 int32_t compact, n, j, l, m, m1;
1134 floatx80 fp0, fp1, fp2, fp3, adjfact, fact1, fact2;
1136 aSig = extractFloatx80Frac(a);
1137 aExp = extractFloatx80Exp(a);
1138 aSign = extractFloatx80Sign(a);
1140 if (aExp == 0x7FFF) {
1141 if ((uint64_t) (aSig << 1)) {
1142 return propagateFloatx80NaNOneArg(a, status);
1144 if (aSign) {
1145 return packFloatx80(0, 0, 0);
1147 return packFloatx80(0, floatx80_infinity.high,
1148 floatx80_infinity.low);
1151 if (aExp == 0 && aSig == 0) {
1152 return packFloatx80(0, one_exp, one_sig);
1155 user_rnd_mode = status->float_rounding_mode;
1156 user_rnd_prec = status->floatx80_rounding_precision;
1157 status->float_rounding_mode = float_round_nearest_even;
1158 status->floatx80_rounding_precision = 80;
1160 fp0 = a;
1162 compact = floatx80_make_compact(aExp, aSig);
1164 if (compact < 0x3FB98000 || compact > 0x400B9B07) {
1165 /* |X| > 16480 LOG2/LOG10 or |X| < 2^(-70) */
1166 if (compact > 0x3FFF8000) { /* |X| > 16480 */
1167 status->float_rounding_mode = user_rnd_mode;
1168 status->floatx80_rounding_precision = user_rnd_prec;
1170 if (aSign) {
1171 return roundAndPackFloatx80(status->floatx80_rounding_precision,
1172 0, -0x1000, aSig, 0, status);
1173 } else {
1174 return roundAndPackFloatx80(status->floatx80_rounding_precision,
1175 0, 0x8000, aSig, 0, status);
1177 } else { /* |X| < 2^(-70) */
1178 status->float_rounding_mode = user_rnd_mode;
1179 status->floatx80_rounding_precision = user_rnd_prec;
1181 a = floatx80_add(fp0, float32_to_floatx80(
1182 make_float32(0x3F800000), status),
1183 status); /* 1 + X */
1185 float_raise(float_flag_inexact, status);
1187 return a;
1189 } else { /* 2^(-70) <= |X| <= 16480 LOG 2 / LOG 10 */
1190 fp1 = fp0; /* X */
1191 fp1 = floatx80_mul(fp1, float64_to_floatx80(
1192 make_float64(0x406A934F0979A371),
1193 status), status); /* X*64*LOG10/LOG2 */
1194 n = floatx80_to_int32(fp1, status); /* N=INT(X*64*LOG10/LOG2) */
1195 fp1 = int32_to_floatx80(n, status);
1197 j = n & 0x3F;
1198 l = n / 64; /* NOTE: this is really arithmetic right shift by 6 */
1199 if (n < 0 && j) {
1200 /* arithmetic right shift is division and
1201 * round towards minus infinity
1203 l--;
1205 m = l / 2; /* NOTE: this is really arithmetic right shift by 1 */
1206 if (l < 0 && (l & 1)) {
1207 /* arithmetic right shift is division and
1208 * round towards minus infinity
1210 m--;
1212 m1 = l - m;
1213 m1 += 0x3FFF; /* ADJFACT IS 2^(M') */
1215 adjfact = packFloatx80(0, m1, one_sig);
1216 fact1 = exp2_tbl[j];
1217 fact1.high += m;
1218 fact2.high = exp2_tbl2[j] >> 16;
1219 fact2.high += m;
1220 fact2.low = (uint64_t)(exp2_tbl2[j] & 0xFFFF);
1221 fact2.low <<= 48;
1223 fp2 = fp1; /* N */
1224 fp1 = floatx80_mul(fp1, float64_to_floatx80(
1225 make_float64(0x3F734413509F8000), status),
1226 status); /* N*(LOG2/64LOG10)_LEAD */
1227 fp3 = packFloatx80(1, 0x3FCD, LIT64(0xC0219DC1DA994FD2));
1228 fp2 = floatx80_mul(fp2, fp3, status); /* N*(LOG2/64LOG10)_TRAIL */
1229 fp0 = floatx80_sub(fp0, fp1, status); /* X - N L_LEAD */
1230 fp0 = floatx80_sub(fp0, fp2, status); /* X - N L_TRAIL */
1231 fp2 = packFloatx80(0, 0x4000, LIT64(0x935D8DDDAAA8AC17)); /* LOG10 */
1232 fp0 = floatx80_mul(fp0, fp2, status); /* R */
1234 /* EXPR */
1235 fp1 = floatx80_mul(fp0, fp0, status); /* S = R*R */
1236 fp2 = float64_to_floatx80(make_float64(0x3F56C16D6F7BD0B2),
1237 status); /* A5 */
1238 fp3 = float64_to_floatx80(make_float64(0x3F811112302C712C),
1239 status); /* A4 */
1240 fp2 = floatx80_mul(fp2, fp1, status); /* S*A5 */
1241 fp3 = floatx80_mul(fp3, fp1, status); /* S*A4 */
1242 fp2 = floatx80_add(fp2, float64_to_floatx80(
1243 make_float64(0x3FA5555555554CC1), status),
1244 status); /* A3+S*A5 */
1245 fp3 = floatx80_add(fp3, float64_to_floatx80(
1246 make_float64(0x3FC5555555554A54), status),
1247 status); /* A2+S*A4 */
1248 fp2 = floatx80_mul(fp2, fp1, status); /* S*(A3+S*A5) */
1249 fp3 = floatx80_mul(fp3, fp1, status); /* S*(A2+S*A4) */
1250 fp2 = floatx80_add(fp2, float64_to_floatx80(
1251 make_float64(0x3FE0000000000000), status),
1252 status); /* A1+S*(A3+S*A5) */
1253 fp3 = floatx80_mul(fp3, fp0, status); /* R*S*(A2+S*A4) */
1255 fp2 = floatx80_mul(fp2, fp1, status); /* S*(A1+S*(A3+S*A5)) */
1256 fp0 = floatx80_add(fp0, fp3, status); /* R+R*S*(A2+S*A4) */
1257 fp0 = floatx80_add(fp0, fp2, status); /* EXP(R) - 1 */
1259 fp0 = floatx80_mul(fp0, fact1, status);
1260 fp0 = floatx80_add(fp0, fact2, status);
1261 fp0 = floatx80_add(fp0, fact1, status);
1263 status->float_rounding_mode = user_rnd_mode;
1264 status->floatx80_rounding_precision = user_rnd_prec;
1266 a = floatx80_mul(fp0, adjfact, status);
1268 float_raise(float_flag_inexact, status);
1270 return a;
1274 /*----------------------------------------------------------------------------
1275 | Tangent
1276 *----------------------------------------------------------------------------*/
1278 floatx80 floatx80_tan(floatx80 a, float_status *status)
1280 flag aSign, xSign;
1281 int32_t aExp, xExp;
1282 uint64_t aSig, xSig;
1284 int8_t user_rnd_mode, user_rnd_prec;
1286 int32_t compact, l, n, j;
1287 floatx80 fp0, fp1, fp2, fp3, fp4, fp5, invtwopi, twopi1, twopi2;
1288 float32 twoto63;
1289 flag endflag;
1291 aSig = extractFloatx80Frac(a);
1292 aExp = extractFloatx80Exp(a);
1293 aSign = extractFloatx80Sign(a);
1295 if (aExp == 0x7FFF) {
1296 if ((uint64_t) (aSig << 1)) {
1297 return propagateFloatx80NaNOneArg(a, status);
1299 float_raise(float_flag_invalid, status);
1300 return floatx80_default_nan(status);
1303 if (aExp == 0 && aSig == 0) {
1304 return packFloatx80(aSign, 0, 0);
1307 user_rnd_mode = status->float_rounding_mode;
1308 user_rnd_prec = status->floatx80_rounding_precision;
1309 status->float_rounding_mode = float_round_nearest_even;
1310 status->floatx80_rounding_precision = 80;
1312 compact = floatx80_make_compact(aExp, aSig);
1314 fp0 = a;
1316 if (compact < 0x3FD78000 || compact > 0x4004BC7E) {
1317 /* 2^(-40) > |X| > 15 PI */
1318 if (compact > 0x3FFF8000) { /* |X| >= 15 PI */
1319 /* REDUCEX */
1320 fp1 = packFloatx80(0, 0, 0);
1321 if (compact == 0x7FFEFFFF) {
1322 twopi1 = packFloatx80(aSign ^ 1, 0x7FFE,
1323 LIT64(0xC90FDAA200000000));
1324 twopi2 = packFloatx80(aSign ^ 1, 0x7FDC,
1325 LIT64(0x85A308D300000000));
1326 fp0 = floatx80_add(fp0, twopi1, status);
1327 fp1 = fp0;
1328 fp0 = floatx80_add(fp0, twopi2, status);
1329 fp1 = floatx80_sub(fp1, fp0, status);
1330 fp1 = floatx80_add(fp1, twopi2, status);
1332 loop:
1333 xSign = extractFloatx80Sign(fp0);
1334 xExp = extractFloatx80Exp(fp0);
1335 xExp -= 0x3FFF;
1336 if (xExp <= 28) {
1337 l = 0;
1338 endflag = 1;
1339 } else {
1340 l = xExp - 27;
1341 endflag = 0;
1343 invtwopi = packFloatx80(0, 0x3FFE - l,
1344 LIT64(0xA2F9836E4E44152A)); /* INVTWOPI */
1345 twopi1 = packFloatx80(0, 0x3FFF + l, LIT64(0xC90FDAA200000000));
1346 twopi2 = packFloatx80(0, 0x3FDD + l, LIT64(0x85A308D300000000));
1348 /* SIGN(INARG)*2^63 IN SGL */
1349 twoto63 = packFloat32(xSign, 0xBE, 0);
1351 fp2 = floatx80_mul(fp0, invtwopi, status);
1352 fp2 = floatx80_add(fp2, float32_to_floatx80(twoto63, status),
1353 status); /* THE FRACT PART OF FP2 IS ROUNDED */
1354 fp2 = floatx80_sub(fp2, float32_to_floatx80(twoto63, status),
1355 status); /* FP2 is N */
1356 fp4 = floatx80_mul(twopi1, fp2, status); /* W = N*P1 */
1357 fp5 = floatx80_mul(twopi2, fp2, status); /* w = N*P2 */
1358 fp3 = floatx80_add(fp4, fp5, status); /* FP3 is P */
1359 fp4 = floatx80_sub(fp4, fp3, status); /* W-P */
1360 fp0 = floatx80_sub(fp0, fp3, status); /* FP0 is A := R - P */
1361 fp4 = floatx80_add(fp4, fp5, status); /* FP4 is p = (W-P)+w */
1362 fp3 = fp0; /* FP3 is A */
1363 fp1 = floatx80_sub(fp1, fp4, status); /* FP1 is a := r - p */
1364 fp0 = floatx80_add(fp0, fp1, status); /* FP0 is R := A+a */
1366 if (endflag > 0) {
1367 n = floatx80_to_int32(fp2, status);
1368 goto tancont;
1370 fp3 = floatx80_sub(fp3, fp0, status); /* A-R */
1371 fp1 = floatx80_add(fp1, fp3, status); /* FP1 is r := (A-R)+a */
1372 goto loop;
1373 } else {
1374 status->float_rounding_mode = user_rnd_mode;
1375 status->floatx80_rounding_precision = user_rnd_prec;
1377 a = floatx80_move(a, status);
1379 float_raise(float_flag_inexact, status);
1381 return a;
1383 } else {
1384 fp1 = floatx80_mul(fp0, float64_to_floatx80(
1385 make_float64(0x3FE45F306DC9C883), status),
1386 status); /* X*2/PI */
1388 n = floatx80_to_int32(fp1, status);
1389 j = 32 + n;
1391 fp0 = floatx80_sub(fp0, pi_tbl[j], status); /* X-Y1 */
1392 fp0 = floatx80_sub(fp0, float32_to_floatx80(pi_tbl2[j], status),
1393 status); /* FP0 IS R = (X-Y1)-Y2 */
1395 tancont:
1396 if (n & 1) {
1397 /* NODD */
1398 fp1 = fp0; /* R */
1399 fp0 = floatx80_mul(fp0, fp0, status); /* S = R*R */
1400 fp3 = float64_to_floatx80(make_float64(0x3EA0B759F50F8688),
1401 status); /* Q4 */
1402 fp2 = float64_to_floatx80(make_float64(0xBEF2BAA5A8924F04),
1403 status); /* P3 */
1404 fp3 = floatx80_mul(fp3, fp0, status); /* SQ4 */
1405 fp2 = floatx80_mul(fp2, fp0, status); /* SP3 */
1406 fp3 = floatx80_add(fp3, float64_to_floatx80(
1407 make_float64(0xBF346F59B39BA65F), status),
1408 status); /* Q3+SQ4 */
1409 fp4 = packFloatx80(0, 0x3FF6, LIT64(0xE073D3FC199C4A00));
1410 fp2 = floatx80_add(fp2, fp4, status); /* P2+SP3 */
1411 fp3 = floatx80_mul(fp3, fp0, status); /* S(Q3+SQ4) */
1412 fp2 = floatx80_mul(fp2, fp0, status); /* S(P2+SP3) */
1413 fp4 = packFloatx80(0, 0x3FF9, LIT64(0xD23CD68415D95FA1));
1414 fp3 = floatx80_add(fp3, fp4, status); /* Q2+S(Q3+SQ4) */
1415 fp4 = packFloatx80(1, 0x3FFC, LIT64(0x8895A6C5FB423BCA));
1416 fp2 = floatx80_add(fp2, fp4, status); /* P1+S(P2+SP3) */
1417 fp3 = floatx80_mul(fp3, fp0, status); /* S(Q2+S(Q3+SQ4)) */
1418 fp2 = floatx80_mul(fp2, fp0, status); /* S(P1+S(P2+SP3)) */
1419 fp4 = packFloatx80(1, 0x3FFD, LIT64(0xEEF57E0DA84BC8CE));
1420 fp3 = floatx80_add(fp3, fp4, status); /* Q1+S(Q2+S(Q3+SQ4)) */
1421 fp2 = floatx80_mul(fp2, fp1, status); /* RS(P1+S(P2+SP3)) */
1422 fp0 = floatx80_mul(fp0, fp3, status); /* S(Q1+S(Q2+S(Q3+SQ4))) */
1423 fp1 = floatx80_add(fp1, fp2, status); /* R+RS(P1+S(P2+SP3)) */
1424 fp0 = floatx80_add(fp0, float32_to_floatx80(
1425 make_float32(0x3F800000), status),
1426 status); /* 1+S(Q1+S(Q2+S(Q3+SQ4))) */
1428 xSign = extractFloatx80Sign(fp1);
1429 xExp = extractFloatx80Exp(fp1);
1430 xSig = extractFloatx80Frac(fp1);
1431 xSign ^= 1;
1432 fp1 = packFloatx80(xSign, xExp, xSig);
1434 status->float_rounding_mode = user_rnd_mode;
1435 status->floatx80_rounding_precision = user_rnd_prec;
1437 a = floatx80_div(fp0, fp1, status);
1439 float_raise(float_flag_inexact, status);
1441 return a;
1442 } else {
1443 fp1 = floatx80_mul(fp0, fp0, status); /* S = R*R */
1444 fp3 = float64_to_floatx80(make_float64(0x3EA0B759F50F8688),
1445 status); /* Q4 */
1446 fp2 = float64_to_floatx80(make_float64(0xBEF2BAA5A8924F04),
1447 status); /* P3 */
1448 fp3 = floatx80_mul(fp3, fp1, status); /* SQ4 */
1449 fp2 = floatx80_mul(fp2, fp1, status); /* SP3 */
1450 fp3 = floatx80_add(fp3, float64_to_floatx80(
1451 make_float64(0xBF346F59B39BA65F), status),
1452 status); /* Q3+SQ4 */
1453 fp4 = packFloatx80(0, 0x3FF6, LIT64(0xE073D3FC199C4A00));
1454 fp2 = floatx80_add(fp2, fp4, status); /* P2+SP3 */
1455 fp3 = floatx80_mul(fp3, fp1, status); /* S(Q3+SQ4) */
1456 fp2 = floatx80_mul(fp2, fp1, status); /* S(P2+SP3) */
1457 fp4 = packFloatx80(0, 0x3FF9, LIT64(0xD23CD68415D95FA1));
1458 fp3 = floatx80_add(fp3, fp4, status); /* Q2+S(Q3+SQ4) */
1459 fp4 = packFloatx80(1, 0x3FFC, LIT64(0x8895A6C5FB423BCA));
1460 fp2 = floatx80_add(fp2, fp4, status); /* P1+S(P2+SP3) */
1461 fp3 = floatx80_mul(fp3, fp1, status); /* S(Q2+S(Q3+SQ4)) */
1462 fp2 = floatx80_mul(fp2, fp1, status); /* S(P1+S(P2+SP3)) */
1463 fp4 = packFloatx80(1, 0x3FFD, LIT64(0xEEF57E0DA84BC8CE));
1464 fp3 = floatx80_add(fp3, fp4, status); /* Q1+S(Q2+S(Q3+SQ4)) */
1465 fp2 = floatx80_mul(fp2, fp0, status); /* RS(P1+S(P2+SP3)) */
1466 fp1 = floatx80_mul(fp1, fp3, status); /* S(Q1+S(Q2+S(Q3+SQ4))) */
1467 fp0 = floatx80_add(fp0, fp2, status); /* R+RS(P1+S(P2+SP3)) */
1468 fp1 = floatx80_add(fp1, float32_to_floatx80(
1469 make_float32(0x3F800000), status),
1470 status); /* 1+S(Q1+S(Q2+S(Q3+SQ4))) */
1472 status->float_rounding_mode = user_rnd_mode;
1473 status->floatx80_rounding_precision = user_rnd_prec;
1475 a = floatx80_div(fp0, fp1, status);
1477 float_raise(float_flag_inexact, status);
1479 return a;
1484 /*----------------------------------------------------------------------------
1485 | Sine
1486 *----------------------------------------------------------------------------*/
1488 floatx80 floatx80_sin(floatx80 a, float_status *status)
1490 flag aSign, xSign;
1491 int32_t aExp, xExp;
1492 uint64_t aSig, xSig;
1494 int8_t user_rnd_mode, user_rnd_prec;
1496 int32_t compact, l, n, j;
1497 floatx80 fp0, fp1, fp2, fp3, fp4, fp5, x, invtwopi, twopi1, twopi2;
1498 float32 posneg1, twoto63;
1499 flag adjn, endflag;
1501 aSig = extractFloatx80Frac(a);
1502 aExp = extractFloatx80Exp(a);
1503 aSign = extractFloatx80Sign(a);
1505 if (aExp == 0x7FFF) {
1506 if ((uint64_t) (aSig << 1)) {
1507 return propagateFloatx80NaNOneArg(a, status);
1509 float_raise(float_flag_invalid, status);
1510 return floatx80_default_nan(status);
1513 if (aExp == 0 && aSig == 0) {
1514 return packFloatx80(aSign, 0, 0);
1517 adjn = 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);
1526 fp0 = a;
1528 if (compact < 0x3FD78000 || compact > 0x4004BC7E) {
1529 /* 2^(-40) > |X| > 15 PI */
1530 if (compact > 0x3FFF8000) { /* |X| >= 15 PI */
1531 /* REDUCEX */
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);
1539 fp1 = fp0;
1540 fp0 = floatx80_add(fp0, twopi2, status);
1541 fp1 = floatx80_sub(fp1, fp0, status);
1542 fp1 = floatx80_add(fp1, twopi2, status);
1544 loop:
1545 xSign = extractFloatx80Sign(fp0);
1546 xExp = extractFloatx80Exp(fp0);
1547 xExp -= 0x3FFF;
1548 if (xExp <= 28) {
1549 l = 0;
1550 endflag = 1;
1551 } else {
1552 l = xExp - 27;
1553 endflag = 0;
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 */
1578 if (endflag > 0) {
1579 n = floatx80_to_int32(fp2, status);
1580 goto sincont;
1582 fp3 = floatx80_sub(fp3, fp0, status); /* A-R */
1583 fp1 = floatx80_add(fp1, fp3, status); /* FP1 is r := (A-R)+a */
1584 goto loop;
1585 } else {
1586 /* SINSM */
1587 fp0 = float32_to_floatx80(make_float32(0x3F800000),
1588 status); /* 1 */
1590 status->float_rounding_mode = user_rnd_mode;
1591 status->floatx80_rounding_precision = user_rnd_prec;
1593 if (adjn) {
1594 /* COSTINY */
1595 a = floatx80_sub(fp0, float32_to_floatx80(
1596 make_float32(0x00800000), status), status);
1597 } else {
1598 /* SINTINY */
1599 a = floatx80_move(a, status);
1601 float_raise(float_flag_inexact, status);
1603 return a;
1605 } else {
1606 fp1 = floatx80_mul(fp0, float64_to_floatx80(
1607 make_float64(0x3FE45F306DC9C883), status),
1608 status); /* X*2/PI */
1610 n = floatx80_to_int32(fp1, status);
1611 j = 32 + n;
1613 fp0 = floatx80_sub(fp0, pi_tbl[j], status); /* X-Y1 */
1614 fp0 = floatx80_sub(fp0, float32_to_floatx80(pi_tbl2[j], status),
1615 status); /* FP0 IS R = (X-Y1)-Y2 */
1617 sincont:
1618 if ((n + adjn) & 1) {
1619 /* COSPOLY */
1620 fp0 = floatx80_mul(fp0, fp0, status); /* FP0 IS S */
1621 fp1 = floatx80_mul(fp0, fp0, status); /* FP1 IS T */
1622 fp2 = float64_to_floatx80(make_float64(0x3D2AC4D0D6011EE3),
1623 status); /* B8 */
1624 fp3 = float64_to_floatx80(make_float64(0xBDA9396F9F45AC19),
1625 status); /* B7 */
1627 xSign = extractFloatx80Sign(fp0); /* X IS S */
1628 xExp = extractFloatx80Exp(fp0);
1629 xSig = extractFloatx80Frac(fp0);
1631 if (((n + adjn) >> 1) & 1) {
1632 xSign ^= 1;
1633 posneg1 = make_float32(0xBF800000); /* -1 */
1634 } else {
1635 xSign ^= 0;
1636 posneg1 = make_float32(0x3F800000); /* 1 */
1637 } /* X IS NOW R'= SGN*R */
1639 fp2 = floatx80_mul(fp2, fp1, status); /* TB8 */
1640 fp3 = floatx80_mul(fp3, fp1, status); /* TB7 */
1641 fp2 = floatx80_add(fp2, float64_to_floatx80(
1642 make_float64(0x3E21EED90612C972), status),
1643 status); /* B6+TB8 */
1644 fp3 = floatx80_add(fp3, float64_to_floatx80(
1645 make_float64(0xBE927E4FB79D9FCF), status),
1646 status); /* B5+TB7 */
1647 fp2 = floatx80_mul(fp2, fp1, status); /* T(B6+TB8) */
1648 fp3 = floatx80_mul(fp3, fp1, status); /* T(B5+TB7) */
1649 fp2 = floatx80_add(fp2, float64_to_floatx80(
1650 make_float64(0x3EFA01A01A01D423), status),
1651 status); /* B4+T(B6+TB8) */
1652 fp4 = packFloatx80(1, 0x3FF5, LIT64(0xB60B60B60B61D438));
1653 fp3 = floatx80_add(fp3, fp4, status); /* B3+T(B5+TB7) */
1654 fp2 = floatx80_mul(fp2, fp1, status); /* T(B4+T(B6+TB8)) */
1655 fp1 = floatx80_mul(fp1, fp3, status); /* T(B3+T(B5+TB7)) */
1656 fp4 = packFloatx80(0, 0x3FFA, LIT64(0xAAAAAAAAAAAAAB5E));
1657 fp2 = floatx80_add(fp2, fp4, status); /* B2+T(B4+T(B6+TB8)) */
1658 fp1 = floatx80_add(fp1, float32_to_floatx80(
1659 make_float32(0xBF000000), status),
1660 status); /* B1+T(B3+T(B5+TB7)) */
1661 fp0 = floatx80_mul(fp0, fp2, status); /* S(B2+T(B4+T(B6+TB8))) */
1662 fp0 = floatx80_add(fp0, fp1, status); /* [B1+T(B3+T(B5+TB7))]+
1663 * [S(B2+T(B4+T(B6+TB8)))]
1666 x = packFloatx80(xSign, xExp, xSig);
1667 fp0 = floatx80_mul(fp0, x, status);
1669 status->float_rounding_mode = user_rnd_mode;
1670 status->floatx80_rounding_precision = user_rnd_prec;
1672 a = floatx80_add(fp0, float32_to_floatx80(posneg1, status), status);
1674 float_raise(float_flag_inexact, status);
1676 return a;
1677 } else {
1678 /* SINPOLY */
1679 xSign = extractFloatx80Sign(fp0); /* X IS R */
1680 xExp = extractFloatx80Exp(fp0);
1681 xSig = extractFloatx80Frac(fp0);
1683 xSign ^= ((n + adjn) >> 1) & 1; /* X IS NOW R'= SGN*R */
1685 fp0 = floatx80_mul(fp0, fp0, status); /* FP0 IS S */
1686 fp1 = floatx80_mul(fp0, fp0, status); /* FP1 IS T */
1687 fp3 = float64_to_floatx80(make_float64(0xBD6AAA77CCC994F5),
1688 status); /* A7 */
1689 fp2 = float64_to_floatx80(make_float64(0x3DE612097AAE8DA1),
1690 status); /* A6 */
1691 fp3 = floatx80_mul(fp3, fp1, status); /* T*A7 */
1692 fp2 = floatx80_mul(fp2, fp1, status); /* T*A6 */
1693 fp3 = floatx80_add(fp3, float64_to_floatx80(
1694 make_float64(0xBE5AE6452A118AE4), status),
1695 status); /* A5+T*A7 */
1696 fp2 = floatx80_add(fp2, float64_to_floatx80(
1697 make_float64(0x3EC71DE3A5341531), status),
1698 status); /* A4+T*A6 */
1699 fp3 = floatx80_mul(fp3, fp1, status); /* T(A5+TA7) */
1700 fp2 = floatx80_mul(fp2, fp1, status); /* T(A4+TA6) */
1701 fp3 = floatx80_add(fp3, float64_to_floatx80(
1702 make_float64(0xBF2A01A01A018B59), status),
1703 status); /* A3+T(A5+TA7) */
1704 fp4 = packFloatx80(0, 0x3FF8, LIT64(0x88888888888859AF));
1705 fp2 = floatx80_add(fp2, fp4, status); /* A2+T(A4+TA6) */
1706 fp1 = floatx80_mul(fp1, fp3, status); /* T(A3+T(A5+TA7)) */
1707 fp2 = floatx80_mul(fp2, fp0, status); /* S(A2+T(A4+TA6)) */
1708 fp4 = packFloatx80(1, 0x3FFC, LIT64(0xAAAAAAAAAAAAAA99));
1709 fp1 = floatx80_add(fp1, fp4, status); /* A1+T(A3+T(A5+TA7)) */
1710 fp1 = floatx80_add(fp1, fp2,
1711 status); /* [A1+T(A3+T(A5+TA7))]+
1712 * [S(A2+T(A4+TA6))]
1715 x = packFloatx80(xSign, xExp, xSig);
1716 fp0 = floatx80_mul(fp0, x, status); /* R'*S */
1717 fp0 = floatx80_mul(fp0, fp1, status); /* SIN(R')-R' */
1719 status->float_rounding_mode = user_rnd_mode;
1720 status->floatx80_rounding_precision = user_rnd_prec;
1722 a = floatx80_add(fp0, x, status);
1724 float_raise(float_flag_inexact, status);
1726 return a;
1731 /*----------------------------------------------------------------------------
1732 | Cosine
1733 *----------------------------------------------------------------------------*/
1735 floatx80 floatx80_cos(floatx80 a, float_status *status)
1737 flag aSign, xSign;
1738 int32_t aExp, xExp;
1739 uint64_t aSig, xSig;
1741 int8_t user_rnd_mode, user_rnd_prec;
1743 int32_t compact, l, n, j;
1744 floatx80 fp0, fp1, fp2, fp3, fp4, fp5, x, invtwopi, twopi1, twopi2;
1745 float32 posneg1, twoto63;
1746 flag adjn, endflag;
1748 aSig = extractFloatx80Frac(a);
1749 aExp = extractFloatx80Exp(a);
1750 aSign = extractFloatx80Sign(a);
1752 if (aExp == 0x7FFF) {
1753 if ((uint64_t) (aSig << 1)) {
1754 return propagateFloatx80NaNOneArg(a, status);
1756 float_raise(float_flag_invalid, status);
1757 return floatx80_default_nan(status);
1760 if (aExp == 0 && aSig == 0) {
1761 return packFloatx80(0, one_exp, one_sig);
1764 adjn = 1;
1766 user_rnd_mode = status->float_rounding_mode;
1767 user_rnd_prec = status->floatx80_rounding_precision;
1768 status->float_rounding_mode = float_round_nearest_even;
1769 status->floatx80_rounding_precision = 80;
1771 compact = floatx80_make_compact(aExp, aSig);
1773 fp0 = a;
1775 if (compact < 0x3FD78000 || compact > 0x4004BC7E) {
1776 /* 2^(-40) > |X| > 15 PI */
1777 if (compact > 0x3FFF8000) { /* |X| >= 15 PI */
1778 /* REDUCEX */
1779 fp1 = packFloatx80(0, 0, 0);
1780 if (compact == 0x7FFEFFFF) {
1781 twopi1 = packFloatx80(aSign ^ 1, 0x7FFE,
1782 LIT64(0xC90FDAA200000000));
1783 twopi2 = packFloatx80(aSign ^ 1, 0x7FDC,
1784 LIT64(0x85A308D300000000));
1785 fp0 = floatx80_add(fp0, twopi1, status);
1786 fp1 = fp0;
1787 fp0 = floatx80_add(fp0, twopi2, status);
1788 fp1 = floatx80_sub(fp1, fp0, status);
1789 fp1 = floatx80_add(fp1, twopi2, status);
1791 loop:
1792 xSign = extractFloatx80Sign(fp0);
1793 xExp = extractFloatx80Exp(fp0);
1794 xExp -= 0x3FFF;
1795 if (xExp <= 28) {
1796 l = 0;
1797 endflag = 1;
1798 } else {
1799 l = xExp - 27;
1800 endflag = 0;
1802 invtwopi = packFloatx80(0, 0x3FFE - l,
1803 LIT64(0xA2F9836E4E44152A)); /* INVTWOPI */
1804 twopi1 = packFloatx80(0, 0x3FFF + l, LIT64(0xC90FDAA200000000));
1805 twopi2 = packFloatx80(0, 0x3FDD + l, LIT64(0x85A308D300000000));
1807 /* SIGN(INARG)*2^63 IN SGL */
1808 twoto63 = packFloat32(xSign, 0xBE, 0);
1810 fp2 = floatx80_mul(fp0, invtwopi, status);
1811 fp2 = floatx80_add(fp2, float32_to_floatx80(twoto63, status),
1812 status); /* THE FRACT PART OF FP2 IS ROUNDED */
1813 fp2 = floatx80_sub(fp2, float32_to_floatx80(twoto63, status),
1814 status); /* FP2 is N */
1815 fp4 = floatx80_mul(twopi1, fp2, status); /* W = N*P1 */
1816 fp5 = floatx80_mul(twopi2, fp2, status); /* w = N*P2 */
1817 fp3 = floatx80_add(fp4, fp5, status); /* FP3 is P */
1818 fp4 = floatx80_sub(fp4, fp3, status); /* W-P */
1819 fp0 = floatx80_sub(fp0, fp3, status); /* FP0 is A := R - P */
1820 fp4 = floatx80_add(fp4, fp5, status); /* FP4 is p = (W-P)+w */
1821 fp3 = fp0; /* FP3 is A */
1822 fp1 = floatx80_sub(fp1, fp4, status); /* FP1 is a := r - p */
1823 fp0 = floatx80_add(fp0, fp1, status); /* FP0 is R := A+a */
1825 if (endflag > 0) {
1826 n = floatx80_to_int32(fp2, status);
1827 goto sincont;
1829 fp3 = floatx80_sub(fp3, fp0, status); /* A-R */
1830 fp1 = floatx80_add(fp1, fp3, status); /* FP1 is r := (A-R)+a */
1831 goto loop;
1832 } else {
1833 /* SINSM */
1834 fp0 = float32_to_floatx80(make_float32(0x3F800000), status); /* 1 */
1836 status->float_rounding_mode = user_rnd_mode;
1837 status->floatx80_rounding_precision = user_rnd_prec;
1839 if (adjn) {
1840 /* COSTINY */
1841 a = floatx80_sub(fp0, float32_to_floatx80(
1842 make_float32(0x00800000), status),
1843 status);
1844 } else {
1845 /* SINTINY */
1846 a = floatx80_move(a, status);
1848 float_raise(float_flag_inexact, status);
1850 return a;
1852 } else {
1853 fp1 = floatx80_mul(fp0, float64_to_floatx80(
1854 make_float64(0x3FE45F306DC9C883), status),
1855 status); /* X*2/PI */
1857 n = floatx80_to_int32(fp1, status);
1858 j = 32 + n;
1860 fp0 = floatx80_sub(fp0, pi_tbl[j], status); /* X-Y1 */
1861 fp0 = floatx80_sub(fp0, float32_to_floatx80(pi_tbl2[j], status),
1862 status); /* FP0 IS R = (X-Y1)-Y2 */
1864 sincont:
1865 if ((n + adjn) & 1) {
1866 /* COSPOLY */
1867 fp0 = floatx80_mul(fp0, fp0, status); /* FP0 IS S */
1868 fp1 = floatx80_mul(fp0, fp0, status); /* FP1 IS T */
1869 fp2 = float64_to_floatx80(make_float64(0x3D2AC4D0D6011EE3),
1870 status); /* B8 */
1871 fp3 = float64_to_floatx80(make_float64(0xBDA9396F9F45AC19),
1872 status); /* B7 */
1874 xSign = extractFloatx80Sign(fp0); /* X IS S */
1875 xExp = extractFloatx80Exp(fp0);
1876 xSig = extractFloatx80Frac(fp0);
1878 if (((n + adjn) >> 1) & 1) {
1879 xSign ^= 1;
1880 posneg1 = make_float32(0xBF800000); /* -1 */
1881 } else {
1882 xSign ^= 0;
1883 posneg1 = make_float32(0x3F800000); /* 1 */
1884 } /* X IS NOW R'= SGN*R */
1886 fp2 = floatx80_mul(fp2, fp1, status); /* TB8 */
1887 fp3 = floatx80_mul(fp3, fp1, status); /* TB7 */
1888 fp2 = floatx80_add(fp2, float64_to_floatx80(
1889 make_float64(0x3E21EED90612C972), status),
1890 status); /* B6+TB8 */
1891 fp3 = floatx80_add(fp3, float64_to_floatx80(
1892 make_float64(0xBE927E4FB79D9FCF), status),
1893 status); /* B5+TB7 */
1894 fp2 = floatx80_mul(fp2, fp1, status); /* T(B6+TB8) */
1895 fp3 = floatx80_mul(fp3, fp1, status); /* T(B5+TB7) */
1896 fp2 = floatx80_add(fp2, float64_to_floatx80(
1897 make_float64(0x3EFA01A01A01D423), status),
1898 status); /* B4+T(B6+TB8) */
1899 fp4 = packFloatx80(1, 0x3FF5, LIT64(0xB60B60B60B61D438));
1900 fp3 = floatx80_add(fp3, fp4, status); /* B3+T(B5+TB7) */
1901 fp2 = floatx80_mul(fp2, fp1, status); /* T(B4+T(B6+TB8)) */
1902 fp1 = floatx80_mul(fp1, fp3, status); /* T(B3+T(B5+TB7)) */
1903 fp4 = packFloatx80(0, 0x3FFA, LIT64(0xAAAAAAAAAAAAAB5E));
1904 fp2 = floatx80_add(fp2, fp4, status); /* B2+T(B4+T(B6+TB8)) */
1905 fp1 = floatx80_add(fp1, float32_to_floatx80(
1906 make_float32(0xBF000000), status),
1907 status); /* B1+T(B3+T(B5+TB7)) */
1908 fp0 = floatx80_mul(fp0, fp2, status); /* S(B2+T(B4+T(B6+TB8))) */
1909 fp0 = floatx80_add(fp0, fp1, status);
1910 /* [B1+T(B3+T(B5+TB7))]+[S(B2+T(B4+T(B6+TB8)))] */
1912 x = packFloatx80(xSign, xExp, xSig);
1913 fp0 = floatx80_mul(fp0, x, status);
1915 status->float_rounding_mode = user_rnd_mode;
1916 status->floatx80_rounding_precision = user_rnd_prec;
1918 a = floatx80_add(fp0, float32_to_floatx80(posneg1, status), status);
1920 float_raise(float_flag_inexact, status);
1922 return a;
1923 } else {
1924 /* SINPOLY */
1925 xSign = extractFloatx80Sign(fp0); /* X IS R */
1926 xExp = extractFloatx80Exp(fp0);
1927 xSig = extractFloatx80Frac(fp0);
1929 xSign ^= ((n + adjn) >> 1) & 1; /* X IS NOW R'= SGN*R */
1931 fp0 = floatx80_mul(fp0, fp0, status); /* FP0 IS S */
1932 fp1 = floatx80_mul(fp0, fp0, status); /* FP1 IS T */
1933 fp3 = float64_to_floatx80(make_float64(0xBD6AAA77CCC994F5),
1934 status); /* A7 */
1935 fp2 = float64_to_floatx80(make_float64(0x3DE612097AAE8DA1),
1936 status); /* A6 */
1937 fp3 = floatx80_mul(fp3, fp1, status); /* T*A7 */
1938 fp2 = floatx80_mul(fp2, fp1, status); /* T*A6 */
1939 fp3 = floatx80_add(fp3, float64_to_floatx80(
1940 make_float64(0xBE5AE6452A118AE4), status),
1941 status); /* A5+T*A7 */
1942 fp2 = floatx80_add(fp2, float64_to_floatx80(
1943 make_float64(0x3EC71DE3A5341531), status),
1944 status); /* A4+T*A6 */
1945 fp3 = floatx80_mul(fp3, fp1, status); /* T(A5+TA7) */
1946 fp2 = floatx80_mul(fp2, fp1, status); /* T(A4+TA6) */
1947 fp3 = floatx80_add(fp3, float64_to_floatx80(
1948 make_float64(0xBF2A01A01A018B59), status),
1949 status); /* A3+T(A5+TA7) */
1950 fp4 = packFloatx80(0, 0x3FF8, LIT64(0x88888888888859AF));
1951 fp2 = floatx80_add(fp2, fp4, status); /* A2+T(A4+TA6) */
1952 fp1 = floatx80_mul(fp1, fp3, status); /* T(A3+T(A5+TA7)) */
1953 fp2 = floatx80_mul(fp2, fp0, status); /* S(A2+T(A4+TA6)) */
1954 fp4 = packFloatx80(1, 0x3FFC, LIT64(0xAAAAAAAAAAAAAA99));
1955 fp1 = floatx80_add(fp1, fp4, status); /* A1+T(A3+T(A5+TA7)) */
1956 fp1 = floatx80_add(fp1, fp2, status);
1957 /* [A1+T(A3+T(A5+TA7))]+[S(A2+T(A4+TA6))] */
1959 x = packFloatx80(xSign, xExp, xSig);
1960 fp0 = floatx80_mul(fp0, x, status); /* R'*S */
1961 fp0 = floatx80_mul(fp0, fp1, status); /* SIN(R')-R' */
1963 status->float_rounding_mode = user_rnd_mode;
1964 status->floatx80_rounding_precision = user_rnd_prec;
1966 a = floatx80_add(fp0, x, status);
1968 float_raise(float_flag_inexact, status);
1970 return a;
1975 /*----------------------------------------------------------------------------
1976 | Arc tangent
1977 *----------------------------------------------------------------------------*/
1979 floatx80 floatx80_atan(floatx80 a, float_status *status)
1981 flag aSign;
1982 int32_t aExp;
1983 uint64_t aSig;
1985 int8_t user_rnd_mode, user_rnd_prec;
1987 int32_t compact, tbl_index;
1988 floatx80 fp0, fp1, fp2, fp3, xsave;
1990 aSig = extractFloatx80Frac(a);
1991 aExp = extractFloatx80Exp(a);
1992 aSign = extractFloatx80Sign(a);
1994 if (aExp == 0x7FFF) {
1995 if ((uint64_t) (aSig << 1)) {
1996 return propagateFloatx80NaNOneArg(a, status);
1998 a = packFloatx80(aSign, piby2_exp, pi_sig);
1999 float_raise(float_flag_inexact, status);
2000 return floatx80_move(a, status);
2003 if (aExp == 0 && aSig == 0) {
2004 return packFloatx80(aSign, 0, 0);
2007 compact = floatx80_make_compact(aExp, aSig);
2009 user_rnd_mode = status->float_rounding_mode;
2010 user_rnd_prec = status->floatx80_rounding_precision;
2011 status->float_rounding_mode = float_round_nearest_even;
2012 status->floatx80_rounding_precision = 80;
2014 if (compact < 0x3FFB8000 || compact > 0x4002FFFF) {
2015 /* |X| >= 16 or |X| < 1/16 */
2016 if (compact > 0x3FFF8000) { /* |X| >= 16 */
2017 if (compact > 0x40638000) { /* |X| > 2^(100) */
2018 fp0 = packFloatx80(aSign, piby2_exp, pi_sig);
2019 fp1 = packFloatx80(aSign, 0x0001, one_sig);
2021 status->float_rounding_mode = user_rnd_mode;
2022 status->floatx80_rounding_precision = user_rnd_prec;
2024 a = floatx80_sub(fp0, fp1, status);
2026 float_raise(float_flag_inexact, status);
2028 return a;
2029 } else {
2030 fp0 = a;
2031 fp1 = packFloatx80(1, one_exp, one_sig); /* -1 */
2032 fp1 = floatx80_div(fp1, fp0, status); /* X' = -1/X */
2033 xsave = fp1;
2034 fp0 = floatx80_mul(fp1, fp1, status); /* Y = X'*X' */
2035 fp1 = floatx80_mul(fp0, fp0, status); /* Z = Y*Y */
2036 fp3 = float64_to_floatx80(make_float64(0xBFB70BF398539E6A),
2037 status); /* C5 */
2038 fp2 = float64_to_floatx80(make_float64(0x3FBC7187962D1D7D),
2039 status); /* C4 */
2040 fp3 = floatx80_mul(fp3, fp1, status); /* Z*C5 */
2041 fp2 = floatx80_mul(fp2, fp1, status); /* Z*C4 */
2042 fp3 = floatx80_add(fp3, float64_to_floatx80(
2043 make_float64(0xBFC24924827107B8), status),
2044 status); /* C3+Z*C5 */
2045 fp2 = floatx80_add(fp2, float64_to_floatx80(
2046 make_float64(0x3FC999999996263E), status),
2047 status); /* C2+Z*C4 */
2048 fp1 = floatx80_mul(fp1, fp3, status); /* Z*(C3+Z*C5) */
2049 fp2 = floatx80_mul(fp2, fp0, status); /* Y*(C2+Z*C4) */
2050 fp1 = floatx80_add(fp1, float64_to_floatx80(
2051 make_float64(0xBFD5555555555536), status),
2052 status); /* C1+Z*(C3+Z*C5) */
2053 fp0 = floatx80_mul(fp0, xsave, status); /* X'*Y */
2054 /* [Y*(C2+Z*C4)]+[C1+Z*(C3+Z*C5)] */
2055 fp1 = floatx80_add(fp1, fp2, status);
2056 /* X'*Y*([B1+Z*(B3+Z*B5)]+[Y*(B2+Z*(B4+Z*B6))]) ?? */
2057 fp0 = floatx80_mul(fp0, fp1, status);
2058 fp0 = floatx80_add(fp0, xsave, status);
2059 fp1 = packFloatx80(aSign, piby2_exp, pi_sig);
2061 status->float_rounding_mode = user_rnd_mode;
2062 status->floatx80_rounding_precision = user_rnd_prec;
2064 a = floatx80_add(fp0, fp1, status);
2066 float_raise(float_flag_inexact, status);
2068 return a;
2070 } else { /* |X| < 1/16 */
2071 if (compact < 0x3FD78000) { /* |X| < 2^(-40) */
2072 status->float_rounding_mode = user_rnd_mode;
2073 status->floatx80_rounding_precision = user_rnd_prec;
2075 a = floatx80_move(a, status);
2077 float_raise(float_flag_inexact, status);
2079 return a;
2080 } else {
2081 fp0 = a;
2082 xsave = a;
2083 fp0 = floatx80_mul(fp0, fp0, status); /* Y = X*X */
2084 fp1 = floatx80_mul(fp0, fp0, status); /* Z = Y*Y */
2085 fp2 = float64_to_floatx80(make_float64(0x3FB344447F876989),
2086 status); /* B6 */
2087 fp3 = float64_to_floatx80(make_float64(0xBFB744EE7FAF45DB),
2088 status); /* B5 */
2089 fp2 = floatx80_mul(fp2, fp1, status); /* Z*B6 */
2090 fp3 = floatx80_mul(fp3, fp1, status); /* Z*B5 */
2091 fp2 = floatx80_add(fp2, float64_to_floatx80(
2092 make_float64(0x3FBC71C646940220), status),
2093 status); /* B4+Z*B6 */
2094 fp3 = floatx80_add(fp3, float64_to_floatx80(
2095 make_float64(0xBFC24924921872F9),
2096 status), status); /* B3+Z*B5 */
2097 fp2 = floatx80_mul(fp2, fp1, status); /* Z*(B4+Z*B6) */
2098 fp1 = floatx80_mul(fp1, fp3, status); /* Z*(B3+Z*B5) */
2099 fp2 = floatx80_add(fp2, float64_to_floatx80(
2100 make_float64(0x3FC9999999998FA9), status),
2101 status); /* B2+Z*(B4+Z*B6) */
2102 fp1 = floatx80_add(fp1, float64_to_floatx80(
2103 make_float64(0xBFD5555555555555), status),
2104 status); /* B1+Z*(B3+Z*B5) */
2105 fp2 = floatx80_mul(fp2, fp0, status); /* Y*(B2+Z*(B4+Z*B6)) */
2106 fp0 = floatx80_mul(fp0, xsave, status); /* X*Y */
2107 /* [B1+Z*(B3+Z*B5)]+[Y*(B2+Z*(B4+Z*B6))] */
2108 fp1 = floatx80_add(fp1, fp2, status);
2109 /* X*Y*([B1+Z*(B3+Z*B5)]+[Y*(B2+Z*(B4+Z*B6))]) */
2110 fp0 = floatx80_mul(fp0, fp1, status);
2112 status->float_rounding_mode = user_rnd_mode;
2113 status->floatx80_rounding_precision = user_rnd_prec;
2115 a = floatx80_add(fp0, xsave, status);
2117 float_raise(float_flag_inexact, status);
2119 return a;
2122 } else {
2123 aSig &= LIT64(0xF800000000000000);
2124 aSig |= LIT64(0x0400000000000000);
2125 xsave = packFloatx80(aSign, aExp, aSig); /* F */
2126 fp0 = a;
2127 fp1 = a; /* X */
2128 fp2 = packFloatx80(0, one_exp, one_sig); /* 1 */
2129 fp1 = floatx80_mul(fp1, xsave, status); /* X*F */
2130 fp0 = floatx80_sub(fp0, xsave, status); /* X-F */
2131 fp1 = floatx80_add(fp1, fp2, status); /* 1 + X*F */
2132 fp0 = floatx80_div(fp0, fp1, status); /* U = (X-F)/(1+X*F) */
2134 tbl_index = compact;
2136 tbl_index &= 0x7FFF0000;
2137 tbl_index -= 0x3FFB0000;
2138 tbl_index >>= 1;
2139 tbl_index += compact & 0x00007800;
2140 tbl_index >>= 11;
2142 fp3 = atan_tbl[tbl_index];
2144 fp3.high |= aSign ? 0x8000 : 0; /* ATAN(F) */
2146 fp1 = floatx80_mul(fp0, fp0, status); /* V = U*U */
2147 fp2 = float64_to_floatx80(make_float64(0xBFF6687E314987D8),
2148 status); /* A3 */
2149 fp2 = floatx80_add(fp2, fp1, status); /* A3+V */
2150 fp2 = floatx80_mul(fp2, fp1, status); /* V*(A3+V) */
2151 fp1 = floatx80_mul(fp1, fp0, status); /* U*V */
2152 fp2 = floatx80_add(fp2, float64_to_floatx80(
2153 make_float64(0x4002AC6934A26DB3), status),
2154 status); /* A2+V*(A3+V) */
2155 fp1 = floatx80_mul(fp1, float64_to_floatx80(
2156 make_float64(0xBFC2476F4E1DA28E), status),
2157 status); /* A1+U*V */
2158 fp1 = floatx80_mul(fp1, fp2, status); /* A1*U*V*(A2+V*(A3+V)) */
2159 fp0 = floatx80_add(fp0, fp1, status); /* ATAN(U) */
2161 status->float_rounding_mode = user_rnd_mode;
2162 status->floatx80_rounding_precision = user_rnd_prec;
2164 a = floatx80_add(fp0, fp3, status); /* ATAN(X) */
2166 float_raise(float_flag_inexact, status);
2168 return a;
2172 /*----------------------------------------------------------------------------
2173 | Arc sine
2174 *----------------------------------------------------------------------------*/
2176 floatx80 floatx80_asin(floatx80 a, float_status *status)
2178 flag aSign;
2179 int32_t aExp;
2180 uint64_t aSig;
2182 int8_t user_rnd_mode, user_rnd_prec;
2184 int32_t compact;
2185 floatx80 fp0, fp1, fp2, one;
2187 aSig = extractFloatx80Frac(a);
2188 aExp = extractFloatx80Exp(a);
2189 aSign = extractFloatx80Sign(a);
2191 if (aExp == 0x7FFF && (uint64_t) (aSig << 1)) {
2192 return propagateFloatx80NaNOneArg(a, status);
2195 if (aExp == 0 && aSig == 0) {
2196 return packFloatx80(aSign, 0, 0);
2199 compact = floatx80_make_compact(aExp, aSig);
2201 if (compact >= 0x3FFF8000) { /* |X| >= 1 */
2202 if (aExp == one_exp && aSig == one_sig) { /* |X| == 1 */
2203 float_raise(float_flag_inexact, status);
2204 a = packFloatx80(aSign, piby2_exp, pi_sig);
2205 return floatx80_move(a, status);
2206 } else { /* |X| > 1 */
2207 float_raise(float_flag_invalid, status);
2208 return floatx80_default_nan(status);
2211 } /* |X| < 1 */
2213 user_rnd_mode = status->float_rounding_mode;
2214 user_rnd_prec = status->floatx80_rounding_precision;
2215 status->float_rounding_mode = float_round_nearest_even;
2216 status->floatx80_rounding_precision = 80;
2218 one = packFloatx80(0, one_exp, one_sig);
2219 fp0 = a;
2221 fp1 = floatx80_sub(one, fp0, status); /* 1 - X */
2222 fp2 = floatx80_add(one, fp0, status); /* 1 + X */
2223 fp1 = floatx80_mul(fp2, fp1, status); /* (1+X)*(1-X) */
2224 fp1 = floatx80_sqrt(fp1, status); /* SQRT((1+X)*(1-X)) */
2225 fp0 = floatx80_div(fp0, fp1, status); /* X/SQRT((1+X)*(1-X)) */
2227 status->float_rounding_mode = user_rnd_mode;
2228 status->floatx80_rounding_precision = user_rnd_prec;
2230 a = floatx80_atan(fp0, status); /* ATAN(X/SQRT((1+X)*(1-X))) */
2232 float_raise(float_flag_inexact, status);
2234 return a;
2237 /*----------------------------------------------------------------------------
2238 | Arc cosine
2239 *----------------------------------------------------------------------------*/
2241 floatx80 floatx80_acos(floatx80 a, float_status *status)
2243 flag aSign;
2244 int32_t aExp;
2245 uint64_t aSig;
2247 int8_t user_rnd_mode, user_rnd_prec;
2249 int32_t compact;
2250 floatx80 fp0, fp1, one;
2252 aSig = extractFloatx80Frac(a);
2253 aExp = extractFloatx80Exp(a);
2254 aSign = extractFloatx80Sign(a);
2256 if (aExp == 0x7FFF && (uint64_t) (aSig << 1)) {
2257 return propagateFloatx80NaNOneArg(a, status);
2259 if (aExp == 0 && aSig == 0) {
2260 float_raise(float_flag_inexact, status);
2261 return roundAndPackFloatx80(status->floatx80_rounding_precision, 0,
2262 piby2_exp, pi_sig, 0, status);
2265 compact = floatx80_make_compact(aExp, aSig);
2267 if (compact >= 0x3FFF8000) { /* |X| >= 1 */
2268 if (aExp == one_exp && aSig == one_sig) { /* |X| == 1 */
2269 if (aSign) { /* X == -1 */
2270 a = packFloatx80(0, pi_exp, pi_sig);
2271 float_raise(float_flag_inexact, status);
2272 return floatx80_move(a, status);
2273 } else { /* X == +1 */
2274 return packFloatx80(0, 0, 0);
2276 } else { /* |X| > 1 */
2277 float_raise(float_flag_invalid, status);
2278 return floatx80_default_nan(status);
2280 } /* |X| < 1 */
2282 user_rnd_mode = status->float_rounding_mode;
2283 user_rnd_prec = status->floatx80_rounding_precision;
2284 status->float_rounding_mode = float_round_nearest_even;
2285 status->floatx80_rounding_precision = 80;
2287 one = packFloatx80(0, one_exp, one_sig);
2288 fp0 = a;
2290 fp1 = floatx80_add(one, fp0, status); /* 1 + X */
2291 fp0 = floatx80_sub(one, fp0, status); /* 1 - X */
2292 fp0 = floatx80_div(fp0, fp1, status); /* (1-X)/(1+X) */
2293 fp0 = floatx80_sqrt(fp0, status); /* SQRT((1-X)/(1+X)) */
2294 fp0 = floatx80_atan(fp0, status); /* ATAN(SQRT((1-X)/(1+X))) */
2296 status->float_rounding_mode = user_rnd_mode;
2297 status->floatx80_rounding_precision = user_rnd_prec;
2299 a = floatx80_add(fp0, fp0, status); /* 2 * ATAN(SQRT((1-X)/(1+X))) */
2301 float_raise(float_flag_inexact, status);
2303 return a;
2306 /*----------------------------------------------------------------------------
2307 | Hyperbolic arc tangent
2308 *----------------------------------------------------------------------------*/
2310 floatx80 floatx80_atanh(floatx80 a, float_status *status)
2312 flag aSign;
2313 int32_t aExp;
2314 uint64_t aSig;
2316 int8_t user_rnd_mode, user_rnd_prec;
2318 int32_t compact;
2319 floatx80 fp0, fp1, fp2, one;
2321 aSig = extractFloatx80Frac(a);
2322 aExp = extractFloatx80Exp(a);
2323 aSign = extractFloatx80Sign(a);
2325 if (aExp == 0x7FFF && (uint64_t) (aSig << 1)) {
2326 return propagateFloatx80NaNOneArg(a, status);
2329 if (aExp == 0 && aSig == 0) {
2330 return packFloatx80(aSign, 0, 0);
2333 compact = floatx80_make_compact(aExp, aSig);
2335 if (compact >= 0x3FFF8000) { /* |X| >= 1 */
2336 if (aExp == one_exp && aSig == one_sig) { /* |X| == 1 */
2337 float_raise(float_flag_divbyzero, status);
2338 return packFloatx80(aSign, floatx80_infinity.high,
2339 floatx80_infinity.low);
2340 } else { /* |X| > 1 */
2341 float_raise(float_flag_invalid, status);
2342 return floatx80_default_nan(status);
2344 } /* |X| < 1 */
2346 user_rnd_mode = status->float_rounding_mode;
2347 user_rnd_prec = status->floatx80_rounding_precision;
2348 status->float_rounding_mode = float_round_nearest_even;
2349 status->floatx80_rounding_precision = 80;
2351 one = packFloatx80(0, one_exp, one_sig);
2352 fp2 = packFloatx80(aSign, 0x3FFE, one_sig); /* SIGN(X) * (1/2) */
2353 fp0 = packFloatx80(0, aExp, aSig); /* Y = |X| */
2354 fp1 = packFloatx80(1, aExp, aSig); /* -Y */
2355 fp0 = floatx80_add(fp0, fp0, status); /* 2Y */
2356 fp1 = floatx80_add(fp1, one, status); /* 1-Y */
2357 fp0 = floatx80_div(fp0, fp1, status); /* Z = 2Y/(1-Y) */
2358 fp0 = floatx80_lognp1(fp0, status); /* LOG1P(Z) */
2360 status->float_rounding_mode = user_rnd_mode;
2361 status->floatx80_rounding_precision = user_rnd_prec;
2363 a = floatx80_mul(fp0, fp2,
2364 status); /* ATANH(X) = SIGN(X) * (1/2) * LOG1P(Z) */
2366 float_raise(float_flag_inexact, status);
2368 return a;
2371 /*----------------------------------------------------------------------------
2372 | e to x minus 1
2373 *----------------------------------------------------------------------------*/
2375 floatx80 floatx80_etoxm1(floatx80 a, float_status *status)
2377 flag aSign;
2378 int32_t aExp;
2379 uint64_t aSig;
2381 int8_t user_rnd_mode, user_rnd_prec;
2383 int32_t compact, n, j, m, m1;
2384 floatx80 fp0, fp1, fp2, fp3, l2, sc, onebysc;
2386 aSig = extractFloatx80Frac(a);
2387 aExp = extractFloatx80Exp(a);
2388 aSign = extractFloatx80Sign(a);
2390 if (aExp == 0x7FFF) {
2391 if ((uint64_t) (aSig << 1)) {
2392 return propagateFloatx80NaNOneArg(a, status);
2394 if (aSign) {
2395 return packFloatx80(aSign, one_exp, one_sig);
2397 return packFloatx80(0, floatx80_infinity.high,
2398 floatx80_infinity.low);
2401 if (aExp == 0 && aSig == 0) {
2402 return packFloatx80(aSign, 0, 0);
2405 user_rnd_mode = status->float_rounding_mode;
2406 user_rnd_prec = status->floatx80_rounding_precision;
2407 status->float_rounding_mode = float_round_nearest_even;
2408 status->floatx80_rounding_precision = 80;
2410 if (aExp >= 0x3FFD) { /* |X| >= 1/4 */
2411 compact = floatx80_make_compact(aExp, aSig);
2413 if (compact <= 0x4004C215) { /* |X| <= 70 log2 */
2414 fp0 = a;
2415 fp1 = a;
2416 fp0 = floatx80_mul(fp0, float32_to_floatx80(
2417 make_float32(0x42B8AA3B), status),
2418 status); /* 64/log2 * X */
2419 n = floatx80_to_int32(fp0, status); /* int(64/log2*X) */
2420 fp0 = int32_to_floatx80(n, status);
2422 j = n & 0x3F; /* J = N mod 64 */
2423 m = n / 64; /* NOTE: this is really arithmetic right shift by 6 */
2424 if (n < 0 && j) {
2425 /* arithmetic right shift is division and
2426 * round towards minus infinity
2428 m--;
2430 m1 = -m;
2431 /*m += 0x3FFF; // biased exponent of 2^(M) */
2432 /*m1 += 0x3FFF; // biased exponent of -2^(-M) */
2434 fp2 = fp0; /* N */
2435 fp0 = floatx80_mul(fp0, float32_to_floatx80(
2436 make_float32(0xBC317218), status),
2437 status); /* N * L1, L1 = lead(-log2/64) */
2438 l2 = packFloatx80(0, 0x3FDC, LIT64(0x82E308654361C4C6));
2439 fp2 = floatx80_mul(fp2, l2, status); /* N * L2, L1+L2 = -log2/64 */
2440 fp0 = floatx80_add(fp0, fp1, status); /* X + N*L1 */
2441 fp0 = floatx80_add(fp0, fp2, status); /* R */
2443 fp1 = floatx80_mul(fp0, fp0, status); /* S = R*R */
2444 fp2 = float32_to_floatx80(make_float32(0x3950097B),
2445 status); /* A6 */
2446 fp2 = floatx80_mul(fp2, fp1, status); /* fp2 is S*A6 */
2447 fp3 = floatx80_mul(float32_to_floatx80(make_float32(0x3AB60B6A),
2448 status), fp1, status); /* fp3 is S*A5 */
2449 fp2 = floatx80_add(fp2, float64_to_floatx80(
2450 make_float64(0x3F81111111174385), status),
2451 status); /* fp2 IS A4+S*A6 */
2452 fp3 = floatx80_add(fp3, float64_to_floatx80(
2453 make_float64(0x3FA5555555554F5A), status),
2454 status); /* fp3 is A3+S*A5 */
2455 fp2 = floatx80_mul(fp2, fp1, status); /* fp2 IS S*(A4+S*A6) */
2456 fp3 = floatx80_mul(fp3, fp1, status); /* fp3 IS S*(A3+S*A5) */
2457 fp2 = floatx80_add(fp2, float64_to_floatx80(
2458 make_float64(0x3FC5555555555555), status),
2459 status); /* fp2 IS A2+S*(A4+S*A6) */
2460 fp3 = floatx80_add(fp3, float32_to_floatx80(
2461 make_float32(0x3F000000), status),
2462 status); /* fp3 IS A1+S*(A3+S*A5) */
2463 fp2 = floatx80_mul(fp2, fp1,
2464 status); /* fp2 IS S*(A2+S*(A4+S*A6)) */
2465 fp1 = floatx80_mul(fp1, fp3,
2466 status); /* fp1 IS S*(A1+S*(A3+S*A5)) */
2467 fp2 = floatx80_mul(fp2, fp0,
2468 status); /* fp2 IS R*S*(A2+S*(A4+S*A6)) */
2469 fp0 = floatx80_add(fp0, fp1,
2470 status); /* fp0 IS R+S*(A1+S*(A3+S*A5)) */
2471 fp0 = floatx80_add(fp0, fp2, status); /* fp0 IS EXP(R) - 1 */
2473 fp0 = floatx80_mul(fp0, exp_tbl[j],
2474 status); /* 2^(J/64)*(Exp(R)-1) */
2476 if (m >= 64) {
2477 fp1 = float32_to_floatx80(exp_tbl2[j], status);
2478 onebysc = packFloatx80(1, m1 + 0x3FFF, one_sig); /* -2^(-M) */
2479 fp1 = floatx80_add(fp1, onebysc, status);
2480 fp0 = floatx80_add(fp0, fp1, status);
2481 fp0 = floatx80_add(fp0, exp_tbl[j], status);
2482 } else if (m < -3) {
2483 fp0 = floatx80_add(fp0, float32_to_floatx80(exp_tbl2[j],
2484 status), status);
2485 fp0 = floatx80_add(fp0, exp_tbl[j], status);
2486 onebysc = packFloatx80(1, m1 + 0x3FFF, one_sig); /* -2^(-M) */
2487 fp0 = floatx80_add(fp0, onebysc, status);
2488 } else { /* -3 <= m <= 63 */
2489 fp1 = exp_tbl[j];
2490 fp0 = floatx80_add(fp0, float32_to_floatx80(exp_tbl2[j],
2491 status), status);
2492 onebysc = packFloatx80(1, m1 + 0x3FFF, one_sig); /* -2^(-M) */
2493 fp1 = floatx80_add(fp1, onebysc, status);
2494 fp0 = floatx80_add(fp0, fp1, status);
2497 sc = packFloatx80(0, m + 0x3FFF, one_sig);
2499 status->float_rounding_mode = user_rnd_mode;
2500 status->floatx80_rounding_precision = user_rnd_prec;
2502 a = floatx80_mul(fp0, sc, status);
2504 float_raise(float_flag_inexact, status);
2506 return a;
2507 } else { /* |X| > 70 log2 */
2508 if (aSign) {
2509 fp0 = float32_to_floatx80(make_float32(0xBF800000),
2510 status); /* -1 */
2512 status->float_rounding_mode = user_rnd_mode;
2513 status->floatx80_rounding_precision = user_rnd_prec;
2515 a = floatx80_add(fp0, float32_to_floatx80(
2516 make_float32(0x00800000), status),
2517 status); /* -1 + 2^(-126) */
2519 float_raise(float_flag_inexact, status);
2521 return a;
2522 } else {
2523 status->float_rounding_mode = user_rnd_mode;
2524 status->floatx80_rounding_precision = user_rnd_prec;
2526 return floatx80_etox(a, status);
2529 } else { /* |X| < 1/4 */
2530 if (aExp >= 0x3FBE) {
2531 fp0 = a;
2532 fp0 = floatx80_mul(fp0, fp0, status); /* S = X*X */
2533 fp1 = float32_to_floatx80(make_float32(0x2F30CAA8),
2534 status); /* B12 */
2535 fp1 = floatx80_mul(fp1, fp0, status); /* S * B12 */
2536 fp2 = float32_to_floatx80(make_float32(0x310F8290),
2537 status); /* B11 */
2538 fp1 = floatx80_add(fp1, float32_to_floatx80(
2539 make_float32(0x32D73220), status),
2540 status); /* B10 */
2541 fp2 = floatx80_mul(fp2, fp0, status);
2542 fp1 = floatx80_mul(fp1, fp0, status);
2543 fp2 = floatx80_add(fp2, float32_to_floatx80(
2544 make_float32(0x3493F281), status),
2545 status); /* B9 */
2546 fp1 = floatx80_add(fp1, float64_to_floatx80(
2547 make_float64(0x3EC71DE3A5774682), status),
2548 status); /* B8 */
2549 fp2 = floatx80_mul(fp2, fp0, status);
2550 fp1 = floatx80_mul(fp1, fp0, status);
2551 fp2 = floatx80_add(fp2, float64_to_floatx80(
2552 make_float64(0x3EFA01A019D7CB68), status),
2553 status); /* B7 */
2554 fp1 = floatx80_add(fp1, float64_to_floatx80(
2555 make_float64(0x3F2A01A01A019DF3), status),
2556 status); /* B6 */
2557 fp2 = floatx80_mul(fp2, fp0, status);
2558 fp1 = floatx80_mul(fp1, fp0, status);
2559 fp2 = floatx80_add(fp2, float64_to_floatx80(
2560 make_float64(0x3F56C16C16C170E2), status),
2561 status); /* B5 */
2562 fp1 = floatx80_add(fp1, float64_to_floatx80(
2563 make_float64(0x3F81111111111111), status),
2564 status); /* B4 */
2565 fp2 = floatx80_mul(fp2, fp0, status);
2566 fp1 = floatx80_mul(fp1, fp0, status);
2567 fp2 = floatx80_add(fp2, float64_to_floatx80(
2568 make_float64(0x3FA5555555555555), status),
2569 status); /* B3 */
2570 fp3 = packFloatx80(0, 0x3FFC, LIT64(0xAAAAAAAAAAAAAAAB));
2571 fp1 = floatx80_add(fp1, fp3, status); /* B2 */
2572 fp2 = floatx80_mul(fp2, fp0, status);
2573 fp1 = floatx80_mul(fp1, fp0, status);
2575 fp2 = floatx80_mul(fp2, fp0, status);
2576 fp1 = floatx80_mul(fp1, a, status);
2578 fp0 = floatx80_mul(fp0, float32_to_floatx80(
2579 make_float32(0x3F000000), status),
2580 status); /* S*B1 */
2581 fp1 = floatx80_add(fp1, fp2, status); /* Q */
2582 fp0 = floatx80_add(fp0, fp1, status); /* S*B1+Q */
2584 status->float_rounding_mode = user_rnd_mode;
2585 status->floatx80_rounding_precision = user_rnd_prec;
2587 a = floatx80_add(fp0, a, status);
2589 float_raise(float_flag_inexact, status);
2591 return a;
2592 } else { /* |X| < 2^(-65) */
2593 sc = packFloatx80(1, 1, one_sig);
2594 fp0 = a;
2596 if (aExp < 0x0033) { /* |X| < 2^(-16382) */
2597 fp0 = floatx80_mul(fp0, float64_to_floatx80(
2598 make_float64(0x48B0000000000000), status),
2599 status);
2600 fp0 = floatx80_add(fp0, sc, status);
2602 status->float_rounding_mode = user_rnd_mode;
2603 status->floatx80_rounding_precision = user_rnd_prec;
2605 a = floatx80_mul(fp0, float64_to_floatx80(
2606 make_float64(0x3730000000000000), status),
2607 status);
2608 } else {
2609 status->float_rounding_mode = user_rnd_mode;
2610 status->floatx80_rounding_precision = user_rnd_prec;
2612 a = floatx80_add(fp0, sc, status);
2615 float_raise(float_flag_inexact, status);
2617 return a;
2622 /*----------------------------------------------------------------------------
2623 | Hyperbolic tangent
2624 *----------------------------------------------------------------------------*/
2626 floatx80 floatx80_tanh(floatx80 a, float_status *status)
2628 flag aSign, vSign;
2629 int32_t aExp, vExp;
2630 uint64_t aSig, vSig;
2632 int8_t user_rnd_mode, user_rnd_prec;
2634 int32_t compact;
2635 floatx80 fp0, fp1;
2636 uint32_t sign;
2638 aSig = extractFloatx80Frac(a);
2639 aExp = extractFloatx80Exp(a);
2640 aSign = extractFloatx80Sign(a);
2642 if (aExp == 0x7FFF) {
2643 if ((uint64_t) (aSig << 1)) {
2644 return propagateFloatx80NaNOneArg(a, status);
2646 return packFloatx80(aSign, one_exp, one_sig);
2649 if (aExp == 0 && aSig == 0) {
2650 return packFloatx80(aSign, 0, 0);
2653 user_rnd_mode = status->float_rounding_mode;
2654 user_rnd_prec = status->floatx80_rounding_precision;
2655 status->float_rounding_mode = float_round_nearest_even;
2656 status->floatx80_rounding_precision = 80;
2658 compact = floatx80_make_compact(aExp, aSig);
2660 if (compact < 0x3FD78000 || compact > 0x3FFFDDCE) {
2661 /* TANHBORS */
2662 if (compact < 0x3FFF8000) {
2663 /* TANHSM */
2664 status->float_rounding_mode = user_rnd_mode;
2665 status->floatx80_rounding_precision = user_rnd_prec;
2667 a = floatx80_move(a, status);
2669 float_raise(float_flag_inexact, status);
2671 return a;
2672 } else {
2673 if (compact > 0x40048AA1) {
2674 /* TANHHUGE */
2675 sign = 0x3F800000;
2676 sign |= aSign ? 0x80000000 : 0x00000000;
2677 fp0 = float32_to_floatx80(make_float32(sign), status);
2678 sign &= 0x80000000;
2679 sign ^= 0x80800000; /* -SIGN(X)*EPS */
2681 status->float_rounding_mode = user_rnd_mode;
2682 status->floatx80_rounding_precision = user_rnd_prec;
2684 a = floatx80_add(fp0, float32_to_floatx80(make_float32(sign),
2685 status), status);
2687 float_raise(float_flag_inexact, status);
2689 return a;
2690 } else {
2691 fp0 = packFloatx80(0, aExp + 1, aSig); /* Y = 2|X| */
2692 fp0 = floatx80_etox(fp0, status); /* FP0 IS EXP(Y) */
2693 fp0 = floatx80_add(fp0, float32_to_floatx80(
2694 make_float32(0x3F800000),
2695 status), status); /* EXP(Y)+1 */
2696 sign = aSign ? 0x80000000 : 0x00000000;
2697 fp1 = floatx80_div(float32_to_floatx80(make_float32(
2698 sign ^ 0xC0000000), status), fp0,
2699 status); /* -SIGN(X)*2 / [EXP(Y)+1] */
2700 fp0 = float32_to_floatx80(make_float32(sign | 0x3F800000),
2701 status); /* SIGN */
2703 status->float_rounding_mode = user_rnd_mode;
2704 status->floatx80_rounding_precision = user_rnd_prec;
2706 a = floatx80_add(fp1, fp0, status);
2708 float_raise(float_flag_inexact, status);
2710 return a;
2713 } else { /* 2**(-40) < |X| < (5/2)LOG2 */
2714 fp0 = packFloatx80(0, aExp + 1, aSig); /* Y = 2|X| */
2715 fp0 = floatx80_etoxm1(fp0, status); /* FP0 IS Z = EXPM1(Y) */
2716 fp1 = floatx80_add(fp0, float32_to_floatx80(make_float32(0x40000000),
2717 status),
2718 status); /* Z+2 */
2720 vSign = extractFloatx80Sign(fp1);
2721 vExp = extractFloatx80Exp(fp1);
2722 vSig = extractFloatx80Frac(fp1);
2724 fp1 = packFloatx80(vSign ^ aSign, vExp, vSig);
2726 status->float_rounding_mode = user_rnd_mode;
2727 status->floatx80_rounding_precision = user_rnd_prec;
2729 a = floatx80_div(fp0, fp1, status);
2731 float_raise(float_flag_inexact, status);
2733 return a;
2737 /*----------------------------------------------------------------------------
2738 | Hyperbolic sine
2739 *----------------------------------------------------------------------------*/
2741 floatx80 floatx80_sinh(floatx80 a, float_status *status)
2743 flag aSign;
2744 int32_t aExp;
2745 uint64_t aSig;
2747 int8_t user_rnd_mode, user_rnd_prec;
2749 int32_t compact;
2750 floatx80 fp0, fp1, fp2;
2751 float32 fact;
2753 aSig = extractFloatx80Frac(a);
2754 aExp = extractFloatx80Exp(a);
2755 aSign = extractFloatx80Sign(a);
2757 if (aExp == 0x7FFF) {
2758 if ((uint64_t) (aSig << 1)) {
2759 return propagateFloatx80NaNOneArg(a, status);
2761 return packFloatx80(aSign, floatx80_infinity.high,
2762 floatx80_infinity.low);
2765 if (aExp == 0 && aSig == 0) {
2766 return packFloatx80(aSign, 0, 0);
2769 user_rnd_mode = status->float_rounding_mode;
2770 user_rnd_prec = status->floatx80_rounding_precision;
2771 status->float_rounding_mode = float_round_nearest_even;
2772 status->floatx80_rounding_precision = 80;
2774 compact = floatx80_make_compact(aExp, aSig);
2776 if (compact > 0x400CB167) {
2777 /* SINHBIG */
2778 if (compact > 0x400CB2B3) {
2779 status->float_rounding_mode = user_rnd_mode;
2780 status->floatx80_rounding_precision = user_rnd_prec;
2782 return roundAndPackFloatx80(status->floatx80_rounding_precision,
2783 aSign, 0x8000, aSig, 0, status);
2784 } else {
2785 fp0 = floatx80_abs(a); /* Y = |X| */
2786 fp0 = floatx80_sub(fp0, float64_to_floatx80(
2787 make_float64(0x40C62D38D3D64634), status),
2788 status); /* (|X|-16381LOG2_LEAD) */
2789 fp0 = floatx80_sub(fp0, float64_to_floatx80(
2790 make_float64(0x3D6F90AEB1E75CC7), status),
2791 status); /* |X| - 16381 LOG2, ACCURATE */
2792 fp0 = floatx80_etox(fp0, status);
2793 fp2 = packFloatx80(aSign, 0x7FFB, one_sig);
2795 status->float_rounding_mode = user_rnd_mode;
2796 status->floatx80_rounding_precision = user_rnd_prec;
2798 a = floatx80_mul(fp0, fp2, status);
2800 float_raise(float_flag_inexact, status);
2802 return a;
2804 } else { /* |X| < 16380 LOG2 */
2805 fp0 = floatx80_abs(a); /* Y = |X| */
2806 fp0 = floatx80_etoxm1(fp0, status); /* FP0 IS Z = EXPM1(Y) */
2807 fp1 = floatx80_add(fp0, float32_to_floatx80(make_float32(0x3F800000),
2808 status), status); /* 1+Z */
2809 fp2 = fp0;
2810 fp0 = floatx80_div(fp0, fp1, status); /* Z/(1+Z) */
2811 fp0 = floatx80_add(fp0, fp2, status);
2813 fact = packFloat32(aSign, 0x7E, 0);
2815 status->float_rounding_mode = user_rnd_mode;
2816 status->floatx80_rounding_precision = user_rnd_prec;
2818 a = floatx80_mul(fp0, float32_to_floatx80(fact, status), status);
2820 float_raise(float_flag_inexact, status);
2822 return a;
2826 /*----------------------------------------------------------------------------
2827 | Hyperbolic cosine
2828 *----------------------------------------------------------------------------*/
2830 floatx80 floatx80_cosh(floatx80 a, float_status *status)
2832 int32_t aExp;
2833 uint64_t aSig;
2835 int8_t user_rnd_mode, user_rnd_prec;
2837 int32_t compact;
2838 floatx80 fp0, fp1;
2840 aSig = extractFloatx80Frac(a);
2841 aExp = extractFloatx80Exp(a);
2843 if (aExp == 0x7FFF) {
2844 if ((uint64_t) (aSig << 1)) {
2845 return propagateFloatx80NaNOneArg(a, status);
2847 return packFloatx80(0, floatx80_infinity.high,
2848 floatx80_infinity.low);
2851 if (aExp == 0 && aSig == 0) {
2852 return packFloatx80(0, one_exp, one_sig);
2855 user_rnd_mode = status->float_rounding_mode;
2856 user_rnd_prec = status->floatx80_rounding_precision;
2857 status->float_rounding_mode = float_round_nearest_even;
2858 status->floatx80_rounding_precision = 80;
2860 compact = floatx80_make_compact(aExp, aSig);
2862 if (compact > 0x400CB167) {
2863 if (compact > 0x400CB2B3) {
2864 status->float_rounding_mode = user_rnd_mode;
2865 status->floatx80_rounding_precision = user_rnd_prec;
2866 return roundAndPackFloatx80(status->floatx80_rounding_precision, 0,
2867 0x8000, one_sig, 0, status);
2868 } else {
2869 fp0 = packFloatx80(0, aExp, aSig);
2870 fp0 = floatx80_sub(fp0, float64_to_floatx80(
2871 make_float64(0x40C62D38D3D64634), status),
2872 status);
2873 fp0 = floatx80_sub(fp0, float64_to_floatx80(
2874 make_float64(0x3D6F90AEB1E75CC7), status),
2875 status);
2876 fp0 = floatx80_etox(fp0, status);
2877 fp1 = packFloatx80(0, 0x7FFB, one_sig);
2879 status->float_rounding_mode = user_rnd_mode;
2880 status->floatx80_rounding_precision = user_rnd_prec;
2882 a = floatx80_mul(fp0, fp1, status);
2884 float_raise(float_flag_inexact, status);
2886 return a;
2890 fp0 = packFloatx80(0, aExp, aSig); /* |X| */
2891 fp0 = floatx80_etox(fp0, status); /* EXP(|X|) */
2892 fp0 = floatx80_mul(fp0, float32_to_floatx80(make_float32(0x3F000000),
2893 status), status); /* (1/2)*EXP(|X|) */
2894 fp1 = float32_to_floatx80(make_float32(0x3E800000), status); /* 1/4 */
2895 fp1 = floatx80_div(fp1, fp0, status); /* 1/(2*EXP(|X|)) */
2897 status->float_rounding_mode = user_rnd_mode;
2898 status->floatx80_rounding_precision = user_rnd_prec;
2900 a = floatx80_add(fp0, fp1, status);
2902 float_raise(float_flag_inexact, status);
2904 return a;