xref: /qemu/target/m68k/softfloat.c (revision 080832e4f4801a28bd1170c49e61f6a0f5f05d03)
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
12   *
13   * Any future contributions to this file will be taken to be licensed under
14   * the Softfloat-2a license unless specifically indicated otherwise.
15   */
16  
17  /*
18   * Portions of this work are licensed under the terms of the GNU GPL,
19   * version 2 or later. See the COPYING file in the top-level directory.
20   */
21  
22  #include "qemu/osdep.h"
23  #include "softfloat.h"
24  #include "fpu/softfloat-macros.h"
25  #include "softfloat_fpsp_tables.h"
26  
27  #define pi_exp      0x4000
28  #define piby2_exp   0x3FFF
29  #define pi_sig      UINT64_C(0xc90fdaa22168c235)
30  
31  static floatx80 propagateFloatx80NaNOneArg(floatx80 a, float_status *status)
32  {
33      if (floatx80_is_signaling_nan(a, status)) {
34          float_raise(float_flag_invalid, status);
35          a = floatx80_silence_nan(a, status);
36      }
37  
38      if (status->default_nan_mode) {
39          return floatx80_default_nan(status);
40      }
41  
42      return a;
43  }
44  
45  /*
46   * Returns the mantissa of the extended double-precision floating-point
47   * value `a'.
48   */
49  
50  floatx80 floatx80_getman(floatx80 a, float_status *status)
51  {
52      bool aSign;
53      int32_t aExp;
54      uint64_t aSig;
55  
56      aSig = extractFloatx80Frac(a);
57      aExp = extractFloatx80Exp(a);
58      aSign = extractFloatx80Sign(a);
59  
60      if (aExp == 0x7FFF) {
61          if ((uint64_t) (aSig << 1)) {
62              return propagateFloatx80NaNOneArg(a , status);
63          }
64          float_raise(float_flag_invalid , status);
65          return floatx80_default_nan(status);
66      }
67  
68      if (aExp == 0) {
69          if (aSig == 0) {
70              return packFloatx80(aSign, 0, 0);
71          }
72          normalizeFloatx80Subnormal(aSig, &aExp, &aSig);
73      }
74  
75      return roundAndPackFloatx80(status->floatx80_rounding_precision, aSign,
76                                  0x3FFF, aSig, 0, status);
77  }
78  
79  /*
80   * Returns the exponent of the extended double-precision floating-point
81   * value `a' as an extended double-precision value.
82   */
83  
84  floatx80 floatx80_getexp(floatx80 a, float_status *status)
85  {
86      bool aSign;
87      int32_t aExp;
88      uint64_t aSig;
89  
90      aSig = extractFloatx80Frac(a);
91      aExp = extractFloatx80Exp(a);
92      aSign = extractFloatx80Sign(a);
93  
94      if (aExp == 0x7FFF) {
95          if ((uint64_t) (aSig << 1)) {
96              return propagateFloatx80NaNOneArg(a , status);
97          }
98          float_raise(float_flag_invalid , status);
99          return floatx80_default_nan(status);
100      }
101  
102      if (aExp == 0) {
103          if (aSig == 0) {
104              return packFloatx80(aSign, 0, 0);
105          }
106          normalizeFloatx80Subnormal(aSig, &aExp, &aSig);
107      }
108  
109      return int32_to_floatx80(aExp - 0x3FFF, status);
110  }
111  
112  /*
113   * Scales extended double-precision floating-point value in operand `a' by
114   * value `b'. The function truncates the value in the second operand 'b' to
115   * an integral value and adds that value to the exponent of the operand 'a'.
116   * The operation performed according to the IEC/IEEE Standard for Binary
117   * Floating-Point Arithmetic.
118   */
119  
120  floatx80 floatx80_scale(floatx80 a, floatx80 b, float_status *status)
121  {
122      bool aSign, bSign;
123      int32_t aExp, bExp, shiftCount;
124      uint64_t aSig, bSig;
125  
126      aSig = extractFloatx80Frac(a);
127      aExp = extractFloatx80Exp(a);
128      aSign = extractFloatx80Sign(a);
129      bSig = extractFloatx80Frac(b);
130      bExp = extractFloatx80Exp(b);
131      bSign = extractFloatx80Sign(b);
132  
133      if (bExp == 0x7FFF) {
134          if ((uint64_t) (bSig << 1) ||
135              ((aExp == 0x7FFF) && (uint64_t) (aSig << 1))) {
136              return propagateFloatx80NaN(a, b, status);
137          }
138          float_raise(float_flag_invalid , status);
139          return floatx80_default_nan(status);
140      }
141      if (aExp == 0x7FFF) {
142          if ((uint64_t) (aSig << 1)) {
143              return propagateFloatx80NaN(a, b, status);
144          }
145          return packFloatx80(aSign, floatx80_infinity.high,
146                              floatx80_infinity.low);
147      }
148      if (aExp == 0) {
149          if (aSig == 0) {
150              return packFloatx80(aSign, 0, 0);
151          }
152          if (bExp < 0x3FFF) {
153              return a;
154          }
155          normalizeFloatx80Subnormal(aSig, &aExp, &aSig);
156      }
157  
158      if (bExp < 0x3FFF) {
159          return a;
160      }
161  
162      if (0x400F < bExp) {
163          aExp = bSign ? -0x6001 : 0xE000;
164          return roundAndPackFloatx80(status->floatx80_rounding_precision,
165                                      aSign, aExp, aSig, 0, status);
166      }
167  
168      shiftCount = 0x403E - bExp;
169      bSig >>= shiftCount;
170      aExp = bSign ? (aExp - bSig) : (aExp + bSig);
171  
172      return roundAndPackFloatx80(status->floatx80_rounding_precision,
173                                  aSign, aExp, aSig, 0, status);
174  }
175  
176  floatx80 floatx80_move(floatx80 a, float_status *status)
177  {
178      bool aSign;
179      int32_t aExp;
180      uint64_t aSig;
181  
182      aSig = extractFloatx80Frac(a);
183      aExp = extractFloatx80Exp(a);
184      aSign = extractFloatx80Sign(a);
185  
186      if (aExp == 0x7FFF) {
187          if ((uint64_t)(aSig << 1)) {
188              return propagateFloatx80NaNOneArg(a, status);
189          }
190          return a;
191      }
192      if (aExp == 0) {
193          if (aSig == 0) {
194              return a;
195          }
196          normalizeRoundAndPackFloatx80(status->floatx80_rounding_precision,
197                                        aSign, aExp, aSig, 0, status);
198      }
199      return roundAndPackFloatx80(status->floatx80_rounding_precision, aSign,
200                                  aExp, aSig, 0, status);
201  }
202  
203  /*
204   * Algorithms for transcendental functions supported by MC68881 and MC68882
205   * mathematical coprocessors. The functions are derived from FPSP library.
206   */
207  
208  #define one_exp     0x3FFF
209  #define one_sig     UINT64_C(0x8000000000000000)
210  
211  /*
212   * Function for compactifying extended double-precision floating point values.
213   */
214  
215  static int32_t floatx80_make_compact(int32_t aExp, uint64_t aSig)
216  {
217      return (aExp << 16) | (aSig >> 48);
218  }
219  
220  /*
221   * Log base e of x plus 1
222   */
223  
224  floatx80 floatx80_lognp1(floatx80 a, float_status *status)
225  {
226      bool aSign;
227      int32_t aExp;
228      uint64_t aSig, fSig;
229  
230      FloatRoundMode user_rnd_mode;
231      FloatX80RoundPrec user_rnd_prec;
232  
233      int32_t compact, j, k;
234      floatx80 fp0, fp1, fp2, fp3, f, logof2, klog2, saveu;
235  
236      aSig = extractFloatx80Frac(a);
237      aExp = extractFloatx80Exp(a);
238      aSign = extractFloatx80Sign(a);
239  
240      if (aExp == 0x7FFF) {
241          if ((uint64_t) (aSig << 1)) {
242              propagateFloatx80NaNOneArg(a, status);
243          }
244          if (aSign) {
245              float_raise(float_flag_invalid, status);
246              return floatx80_default_nan(status);
247          }
248          return packFloatx80(0, floatx80_infinity.high, floatx80_infinity.low);
249      }
250  
251      if (aExp == 0 && aSig == 0) {
252          return packFloatx80(aSign, 0, 0);
253      }
254  
255      if (aSign && aExp >= one_exp) {
256          if (aExp == one_exp && aSig == one_sig) {
257              float_raise(float_flag_divbyzero, status);
258              return packFloatx80(aSign, floatx80_infinity.high,
259                                  floatx80_infinity.low);
260          }
261          float_raise(float_flag_invalid, status);
262          return floatx80_default_nan(status);
263      }
264  
265      if (aExp < 0x3f99 || (aExp == 0x3f99 && aSig == one_sig)) {
266          /* <= min threshold */
267          float_raise(float_flag_inexact, status);
268          return floatx80_move(a, status);
269      }
270  
271      user_rnd_mode = status->float_rounding_mode;
272      user_rnd_prec = status->floatx80_rounding_precision;
273      status->float_rounding_mode = float_round_nearest_even;
274      status->floatx80_rounding_precision = floatx80_precision_x;
275  
276      compact = floatx80_make_compact(aExp, aSig);
277  
278      fp0 = a; /* Z */
279      fp1 = a;
280  
281      fp0 = floatx80_add(fp0, float32_to_floatx80(make_float32(0x3F800000),
282                         status), status); /* X = (1+Z) */
283  
284      aExp = extractFloatx80Exp(fp0);
285      aSig = extractFloatx80Frac(fp0);
286  
287      compact = floatx80_make_compact(aExp, aSig);
288  
289      if (compact < 0x3FFE8000 || compact > 0x3FFFC000) {
290          /* |X| < 1/2 or |X| > 3/2 */
291          k = aExp - 0x3FFF;
292          fp1 = int32_to_floatx80(k, status);
293  
294          fSig = (aSig & UINT64_C(0xFE00000000000000)) | UINT64_C(0x0100000000000000);
295          j = (fSig >> 56) & 0x7E; /* DISPLACEMENT FOR 1/F */
296  
297          f = packFloatx80(0, 0x3FFF, fSig); /* F */
298          fp0 = packFloatx80(0, 0x3FFF, aSig); /* Y */
299  
300          fp0 = floatx80_sub(fp0, f, status); /* Y-F */
301  
302      lp1cont1:
303          /* LP1CONT1 */
304          fp0 = floatx80_mul(fp0, log_tbl[j], status); /* FP0 IS U = (Y-F)/F */
305          logof2 = packFloatx80(0, 0x3FFE, UINT64_C(0xB17217F7D1CF79AC));
306          klog2 = floatx80_mul(fp1, logof2, status); /* FP1 IS K*LOG2 */
307          fp2 = floatx80_mul(fp0, fp0, status); /* FP2 IS V=U*U */
308  
309          fp3 = fp2;
310          fp1 = fp2;
311  
312          fp1 = floatx80_mul(fp1, float64_to_floatx80(
313                             make_float64(0x3FC2499AB5E4040B), status),
314                             status); /* V*A6 */
315          fp2 = floatx80_mul(fp2, float64_to_floatx80(
316                             make_float64(0xBFC555B5848CB7DB), status),
317                             status); /* V*A5 */
318          fp1 = floatx80_add(fp1, float64_to_floatx80(
319                             make_float64(0x3FC99999987D8730), status),
320                             status); /* A4+V*A6 */
321          fp2 = floatx80_add(fp2, float64_to_floatx80(
322                             make_float64(0xBFCFFFFFFF6F7E97), status),
323                             status); /* A3+V*A5 */
324          fp1 = floatx80_mul(fp1, fp3, status); /* V*(A4+V*A6) */
325          fp2 = floatx80_mul(fp2, fp3, status); /* V*(A3+V*A5) */
326          fp1 = floatx80_add(fp1, float64_to_floatx80(
327                             make_float64(0x3FD55555555555A4), status),
328                             status); /* A2+V*(A4+V*A6) */
329          fp2 = floatx80_add(fp2, float64_to_floatx80(
330                             make_float64(0xBFE0000000000008), status),
331                             status); /* A1+V*(A3+V*A5) */
332          fp1 = floatx80_mul(fp1, fp3, status); /* V*(A2+V*(A4+V*A6)) */
333          fp2 = floatx80_mul(fp2, fp3, status); /* V*(A1+V*(A3+V*A5)) */
334          fp1 = floatx80_mul(fp1, fp0, status); /* U*V*(A2+V*(A4+V*A6)) */
335          fp0 = floatx80_add(fp0, fp2, status); /* U+V*(A1+V*(A3+V*A5)) */
336  
337          fp1 = floatx80_add(fp1, log_tbl[j + 1],
338                             status); /* LOG(F)+U*V*(A2+V*(A4+V*A6)) */
339          fp0 = floatx80_add(fp0, fp1, status); /* FP0 IS LOG(F) + LOG(1+U) */
340  
341          status->float_rounding_mode = user_rnd_mode;
342          status->floatx80_rounding_precision = user_rnd_prec;
343  
344          a = floatx80_add(fp0, klog2, status);
345  
346          float_raise(float_flag_inexact, status);
347  
348          return a;
349      } else if (compact < 0x3FFEF07D || compact > 0x3FFF8841) {
350          /* |X| < 1/16 or |X| > -1/16 */
351          /* LP1CARE */
352          fSig = (aSig & UINT64_C(0xFE00000000000000)) | UINT64_C(0x0100000000000000);
353          f = packFloatx80(0, 0x3FFF, fSig); /* F */
354          j = (fSig >> 56) & 0x7E; /* DISPLACEMENT FOR 1/F */
355  
356          if (compact >= 0x3FFF8000) { /* 1+Z >= 1 */
357              /* KISZERO */
358              fp0 = floatx80_sub(float32_to_floatx80(make_float32(0x3F800000),
359                                 status), f, status); /* 1-F */
360              fp0 = floatx80_add(fp0, fp1, status); /* FP0 IS Y-F = (1-F)+Z */
361              fp1 = packFloatx80(0, 0, 0); /* K = 0 */
362          } else {
363              /* KISNEG */
364              fp0 = floatx80_sub(float32_to_floatx80(make_float32(0x40000000),
365                                 status), f, status); /* 2-F */
366              fp1 = floatx80_add(fp1, fp1, status); /* 2Z */
367              fp0 = floatx80_add(fp0, fp1, status); /* FP0 IS Y-F = (2-F)+2Z */
368              fp1 = packFloatx80(1, one_exp, one_sig); /* K = -1 */
369          }
370          goto lp1cont1;
371      } else {
372          /* LP1ONE16 */
373          fp1 = floatx80_add(fp1, fp1, status); /* FP1 IS 2Z */
374          fp0 = floatx80_add(fp0, float32_to_floatx80(make_float32(0x3F800000),
375                             status), status); /* FP0 IS 1+X */
376  
377          /* LP1CONT2 */
378          fp1 = floatx80_div(fp1, fp0, status); /* U */
379          saveu = fp1;
380          fp0 = floatx80_mul(fp1, fp1, status); /* FP0 IS V = U*U */
381          fp1 = floatx80_mul(fp0, fp0, status); /* FP1 IS W = V*V */
382  
383          fp3 = float64_to_floatx80(make_float64(0x3F175496ADD7DAD6),
384                                    status); /* B5 */
385          fp2 = float64_to_floatx80(make_float64(0x3F3C71C2FE80C7E0),
386                                    status); /* B4 */
387          fp3 = floatx80_mul(fp3, fp1, status); /* W*B5 */
388          fp2 = floatx80_mul(fp2, fp1, status); /* W*B4 */
389          fp3 = floatx80_add(fp3, float64_to_floatx80(
390                             make_float64(0x3F624924928BCCFF), status),
391                             status); /* B3+W*B5 */
392          fp2 = floatx80_add(fp2, float64_to_floatx80(
393                             make_float64(0x3F899999999995EC), status),
394                             status); /* B2+W*B4 */
395          fp1 = floatx80_mul(fp1, fp3, status); /* W*(B3+W*B5) */
396          fp2 = floatx80_mul(fp2, fp0, status); /* V*(B2+W*B4) */
397          fp1 = floatx80_add(fp1, float64_to_floatx80(
398                             make_float64(0x3FB5555555555555), status),
399                             status); /* B1+W*(B3+W*B5) */
400  
401          fp0 = floatx80_mul(fp0, saveu, status); /* FP0 IS U*V */
402          fp1 = floatx80_add(fp1, fp2,
403                             status); /* B1+W*(B3+W*B5) + V*(B2+W*B4) */
404          fp0 = floatx80_mul(fp0, fp1,
405                             status); /* U*V*([B1+W*(B3+W*B5)] + [V*(B2+W*B4)]) */
406  
407          status->float_rounding_mode = user_rnd_mode;
408          status->floatx80_rounding_precision = user_rnd_prec;
409  
410          a = floatx80_add(fp0, saveu, status);
411  
412          /*if (!floatx80_is_zero(a)) { */
413              float_raise(float_flag_inexact, status);
414          /*} */
415  
416          return a;
417      }
418  }
419  
420  /*
421   * Log base e
422   */
423  
424  floatx80 floatx80_logn(floatx80 a, float_status *status)
425  {
426      bool aSign;
427      int32_t aExp;
428      uint64_t aSig, fSig;
429  
430      FloatRoundMode user_rnd_mode;
431      FloatX80RoundPrec user_rnd_prec;
432  
433      int32_t compact, j, k, adjk;
434      floatx80 fp0, fp1, fp2, fp3, f, logof2, klog2, saveu;
435  
436      aSig = extractFloatx80Frac(a);
437      aExp = extractFloatx80Exp(a);
438      aSign = extractFloatx80Sign(a);
439  
440      if (aExp == 0x7FFF) {
441          if ((uint64_t) (aSig << 1)) {
442              propagateFloatx80NaNOneArg(a, status);
443          }
444          if (aSign == 0) {
445              return packFloatx80(0, floatx80_infinity.high,
446                                  floatx80_infinity.low);
447          }
448      }
449  
450      adjk = 0;
451  
452      if (aExp == 0) {
453          if (aSig == 0) { /* zero */
454              float_raise(float_flag_divbyzero, status);
455              return packFloatx80(1, floatx80_infinity.high,
456                                  floatx80_infinity.low);
457          }
458          if ((aSig & one_sig) == 0) { /* denormal */
459              normalizeFloatx80Subnormal(aSig, &aExp, &aSig);
460              adjk = -100;
461              aExp += 100;
462              a = packFloatx80(aSign, aExp, aSig);
463          }
464      }
465  
466      if (aSign) {
467          float_raise(float_flag_invalid, status);
468          return floatx80_default_nan(status);
469      }
470  
471      user_rnd_mode = status->float_rounding_mode;
472      user_rnd_prec = status->floatx80_rounding_precision;
473      status->float_rounding_mode = float_round_nearest_even;
474      status->floatx80_rounding_precision = floatx80_precision_x;
475  
476      compact = floatx80_make_compact(aExp, aSig);
477  
478      if (compact < 0x3FFEF07D || compact > 0x3FFF8841) {
479          /* |X| < 15/16 or |X| > 17/16 */
480          k = aExp - 0x3FFF;
481          k += adjk;
482          fp1 = int32_to_floatx80(k, status);
483  
484          fSig = (aSig & UINT64_C(0xFE00000000000000)) | UINT64_C(0x0100000000000000);
485          j = (fSig >> 56) & 0x7E; /* DISPLACEMENT FOR 1/F */
486  
487          f = packFloatx80(0, 0x3FFF, fSig); /* F */
488          fp0 = packFloatx80(0, 0x3FFF, aSig); /* Y */
489  
490          fp0 = floatx80_sub(fp0, f, status); /* Y-F */
491  
492          /* LP1CONT1 */
493          fp0 = floatx80_mul(fp0, log_tbl[j], status); /* FP0 IS U = (Y-F)/F */
494          logof2 = packFloatx80(0, 0x3FFE, UINT64_C(0xB17217F7D1CF79AC));
495          klog2 = floatx80_mul(fp1, logof2, status); /* FP1 IS K*LOG2 */
496          fp2 = floatx80_mul(fp0, fp0, status); /* FP2 IS V=U*U */
497  
498          fp3 = fp2;
499          fp1 = fp2;
500  
501          fp1 = floatx80_mul(fp1, float64_to_floatx80(
502                             make_float64(0x3FC2499AB5E4040B), status),
503                             status); /* V*A6 */
504          fp2 = floatx80_mul(fp2, float64_to_floatx80(
505                             make_float64(0xBFC555B5848CB7DB), status),
506                             status); /* V*A5 */
507          fp1 = floatx80_add(fp1, float64_to_floatx80(
508                             make_float64(0x3FC99999987D8730), status),
509                             status); /* A4+V*A6 */
510          fp2 = floatx80_add(fp2, float64_to_floatx80(
511                             make_float64(0xBFCFFFFFFF6F7E97), status),
512                             status); /* A3+V*A5 */
513          fp1 = floatx80_mul(fp1, fp3, status); /* V*(A4+V*A6) */
514          fp2 = floatx80_mul(fp2, fp3, status); /* V*(A3+V*A5) */
515          fp1 = floatx80_add(fp1, float64_to_floatx80(
516                             make_float64(0x3FD55555555555A4), status),
517                             status); /* A2+V*(A4+V*A6) */
518          fp2 = floatx80_add(fp2, float64_to_floatx80(
519                             make_float64(0xBFE0000000000008), status),
520                             status); /* A1+V*(A3+V*A5) */
521          fp1 = floatx80_mul(fp1, fp3, status); /* V*(A2+V*(A4+V*A6)) */
522          fp2 = floatx80_mul(fp2, fp3, status); /* V*(A1+V*(A3+V*A5)) */
523          fp1 = floatx80_mul(fp1, fp0, status); /* U*V*(A2+V*(A4+V*A6)) */
524          fp0 = floatx80_add(fp0, fp2, status); /* U+V*(A1+V*(A3+V*A5)) */
525  
526          fp1 = floatx80_add(fp1, log_tbl[j + 1],
527                             status); /* LOG(F)+U*V*(A2+V*(A4+V*A6)) */
528          fp0 = floatx80_add(fp0, fp1, status); /* FP0 IS LOG(F) + LOG(1+U) */
529  
530          status->float_rounding_mode = user_rnd_mode;
531          status->floatx80_rounding_precision = user_rnd_prec;
532  
533          a = floatx80_add(fp0, klog2, status);
534  
535          float_raise(float_flag_inexact, status);
536  
537          return a;
538      } else { /* |X-1| >= 1/16 */
539          fp0 = a;
540          fp1 = a;
541          fp1 = floatx80_sub(fp1, float32_to_floatx80(make_float32(0x3F800000),
542                             status), status); /* FP1 IS X-1 */
543          fp0 = floatx80_add(fp0, float32_to_floatx80(make_float32(0x3F800000),
544                             status), status); /* FP0 IS X+1 */
545          fp1 = floatx80_add(fp1, fp1, status); /* FP1 IS 2(X-1) */
546  
547          /* LP1CONT2 */
548          fp1 = floatx80_div(fp1, fp0, status); /* U */
549          saveu = fp1;
550          fp0 = floatx80_mul(fp1, fp1, status); /* FP0 IS V = U*U */
551          fp1 = floatx80_mul(fp0, fp0, status); /* FP1 IS W = V*V */
552  
553          fp3 = float64_to_floatx80(make_float64(0x3F175496ADD7DAD6),
554                                    status); /* B5 */
555          fp2 = float64_to_floatx80(make_float64(0x3F3C71C2FE80C7E0),
556                                    status); /* B4 */
557          fp3 = floatx80_mul(fp3, fp1, status); /* W*B5 */
558          fp2 = floatx80_mul(fp2, fp1, status); /* W*B4 */
559          fp3 = floatx80_add(fp3, float64_to_floatx80(
560                             make_float64(0x3F624924928BCCFF), status),
561                             status); /* B3+W*B5 */
562          fp2 = floatx80_add(fp2, float64_to_floatx80(
563                             make_float64(0x3F899999999995EC), status),
564                             status); /* B2+W*B4 */
565          fp1 = floatx80_mul(fp1, fp3, status); /* W*(B3+W*B5) */
566          fp2 = floatx80_mul(fp2, fp0, status); /* V*(B2+W*B4) */
567          fp1 = floatx80_add(fp1, float64_to_floatx80(
568                             make_float64(0x3FB5555555555555), status),
569                             status); /* B1+W*(B3+W*B5) */
570  
571          fp0 = floatx80_mul(fp0, saveu, status); /* FP0 IS U*V */
572          fp1 = floatx80_add(fp1, fp2, status); /* B1+W*(B3+W*B5) + V*(B2+W*B4) */
573          fp0 = floatx80_mul(fp0, fp1,
574                             status); /* U*V*([B1+W*(B3+W*B5)] + [V*(B2+W*B4)]) */
575  
576          status->float_rounding_mode = user_rnd_mode;
577          status->floatx80_rounding_precision = user_rnd_prec;
578  
579          a = floatx80_add(fp0, saveu, status);
580  
581          /*if (!floatx80_is_zero(a)) { */
582              float_raise(float_flag_inexact, status);
583          /*} */
584  
585          return a;
586      }
587  }
588  
589  /*
590   * Log base 10
591   */
592  
593  floatx80 floatx80_log10(floatx80 a, float_status *status)
594  {
595      bool aSign;
596      int32_t aExp;
597      uint64_t aSig;
598  
599      FloatRoundMode user_rnd_mode;
600      FloatX80RoundPrec user_rnd_prec;
601  
602      floatx80 fp0, fp1;
603  
604      aSig = extractFloatx80Frac(a);
605      aExp = extractFloatx80Exp(a);
606      aSign = extractFloatx80Sign(a);
607  
608      if (aExp == 0x7FFF) {
609          if ((uint64_t) (aSig << 1)) {
610              propagateFloatx80NaNOneArg(a, status);
611          }
612          if (aSign == 0) {
613              return packFloatx80(0, floatx80_infinity.high,
614                                  floatx80_infinity.low);
615          }
616      }
617  
618      if (aExp == 0 && aSig == 0) {
619          float_raise(float_flag_divbyzero, status);
620          return packFloatx80(1, floatx80_infinity.high,
621                              floatx80_infinity.low);
622      }
623  
624      if (aSign) {
625          float_raise(float_flag_invalid, status);
626          return floatx80_default_nan(status);
627      }
628  
629      user_rnd_mode = status->float_rounding_mode;
630      user_rnd_prec = status->floatx80_rounding_precision;
631      status->float_rounding_mode = float_round_nearest_even;
632      status->floatx80_rounding_precision = floatx80_precision_x;
633  
634      fp0 = floatx80_logn(a, status);
635      fp1 = packFloatx80(0, 0x3FFD, UINT64_C(0xDE5BD8A937287195)); /* INV_L10 */
636  
637      status->float_rounding_mode = user_rnd_mode;
638      status->floatx80_rounding_precision = user_rnd_prec;
639  
640      a = floatx80_mul(fp0, fp1, status); /* LOGN(X)*INV_L10 */
641  
642      float_raise(float_flag_inexact, status);
643  
644      return a;
645  }
646  
647  /*
648   * Log base 2
649   */
650  
651  floatx80 floatx80_log2(floatx80 a, float_status *status)
652  {
653      bool aSign;
654      int32_t aExp;
655      uint64_t aSig;
656  
657      FloatRoundMode user_rnd_mode;
658      FloatX80RoundPrec user_rnd_prec;
659  
660      floatx80 fp0, fp1;
661  
662      aSig = extractFloatx80Frac(a);
663      aExp = extractFloatx80Exp(a);
664      aSign = extractFloatx80Sign(a);
665  
666      if (aExp == 0x7FFF) {
667          if ((uint64_t) (aSig << 1)) {
668              propagateFloatx80NaNOneArg(a, status);
669          }
670          if (aSign == 0) {
671              return packFloatx80(0, floatx80_infinity.high,
672                                  floatx80_infinity.low);
673          }
674      }
675  
676      if (aExp == 0) {
677          if (aSig == 0) {
678              float_raise(float_flag_divbyzero, status);
679              return packFloatx80(1, floatx80_infinity.high,
680                                  floatx80_infinity.low);
681          }
682          normalizeFloatx80Subnormal(aSig, &aExp, &aSig);
683      }
684  
685      if (aSign) {
686          float_raise(float_flag_invalid, status);
687          return floatx80_default_nan(status);
688      }
689  
690      user_rnd_mode = status->float_rounding_mode;
691      user_rnd_prec = status->floatx80_rounding_precision;
692      status->float_rounding_mode = float_round_nearest_even;
693      status->floatx80_rounding_precision = floatx80_precision_x;
694  
695      if (aSig == one_sig) { /* X is 2^k */
696          status->float_rounding_mode = user_rnd_mode;
697          status->floatx80_rounding_precision = user_rnd_prec;
698  
699          a = int32_to_floatx80(aExp - 0x3FFF, status);
700      } else {
701          fp0 = floatx80_logn(a, status);
702          fp1 = packFloatx80(0, 0x3FFF, UINT64_C(0xB8AA3B295C17F0BC)); /* INV_L2 */
703  
704          status->float_rounding_mode = user_rnd_mode;
705          status->floatx80_rounding_precision = user_rnd_prec;
706  
707          a = floatx80_mul(fp0, fp1, status); /* LOGN(X)*INV_L2 */
708      }
709  
710      float_raise(float_flag_inexact, status);
711  
712      return a;
713  }
714  
715  /*
716   * e to x
717   */
718  
719  floatx80 floatx80_etox(floatx80 a, float_status *status)
720  {
721      bool aSign;
722      int32_t aExp;
723      uint64_t aSig;
724  
725      FloatRoundMode user_rnd_mode;
726      FloatX80RoundPrec user_rnd_prec;
727  
728      int32_t compact, n, j, k, m, m1;
729      floatx80 fp0, fp1, fp2, fp3, l2, scale, adjscale;
730      bool adjflag;
731  
732      aSig = extractFloatx80Frac(a);
733      aExp = extractFloatx80Exp(a);
734      aSign = extractFloatx80Sign(a);
735  
736      if (aExp == 0x7FFF) {
737          if ((uint64_t) (aSig << 1)) {
738              return propagateFloatx80NaNOneArg(a, status);
739          }
740          if (aSign) {
741              return packFloatx80(0, 0, 0);
742          }
743          return packFloatx80(0, floatx80_infinity.high,
744                              floatx80_infinity.low);
745      }
746  
747      if (aExp == 0 && aSig == 0) {
748          return packFloatx80(0, one_exp, one_sig);
749      }
750  
751      user_rnd_mode = status->float_rounding_mode;
752      user_rnd_prec = status->floatx80_rounding_precision;
753      status->float_rounding_mode = float_round_nearest_even;
754      status->floatx80_rounding_precision = floatx80_precision_x;
755  
756      adjflag = 0;
757  
758      if (aExp >= 0x3FBE) { /* |X| >= 2^(-65) */
759          compact = floatx80_make_compact(aExp, aSig);
760  
761          if (compact < 0x400CB167) { /* |X| < 16380 log2 */
762              fp0 = a;
763              fp1 = a;
764              fp0 = floatx80_mul(fp0, float32_to_floatx80(
765                                 make_float32(0x42B8AA3B), status),
766                                 status); /* 64/log2 * X */
767              adjflag = 0;
768              n = floatx80_to_int32(fp0, status); /* int(64/log2*X) */
769              fp0 = int32_to_floatx80(n, status);
770  
771              j = n & 0x3F; /* J = N mod 64 */
772              m = n / 64; /* NOTE: this is really arithmetic right shift by 6 */
773              if (n < 0 && j) {
774                  /*
775                   * arithmetic right shift is division and
776                   * round towards minus infinity
777                   */
778                  m--;
779              }
780              m += 0x3FFF; /* biased exponent of 2^(M) */
781  
782          expcont1:
783              fp2 = fp0; /* N */
784              fp0 = floatx80_mul(fp0, float32_to_floatx80(
785                                 make_float32(0xBC317218), status),
786                                 status); /* N * L1, L1 = lead(-log2/64) */
787              l2 = packFloatx80(0, 0x3FDC, UINT64_C(0x82E308654361C4C6));
788              fp2 = floatx80_mul(fp2, l2, status); /* N * L2, L1+L2 = -log2/64 */
789              fp0 = floatx80_add(fp0, fp1, status); /* X + N*L1 */
790              fp0 = floatx80_add(fp0, fp2, status); /* R */
791  
792              fp1 = floatx80_mul(fp0, fp0, status); /* S = R*R */
793              fp2 = float32_to_floatx80(make_float32(0x3AB60B70),
794                                        status); /* A5 */
795              fp2 = floatx80_mul(fp2, fp1, status); /* fp2 is S*A5 */
796              fp3 = floatx80_mul(float32_to_floatx80(make_float32(0x3C088895),
797                                 status), fp1,
798                                 status); /* fp3 is S*A4 */
799              fp2 = floatx80_add(fp2, float64_to_floatx80(make_float64(
800                                 0x3FA5555555554431), status),
801                                 status); /* fp2 is A3+S*A5 */
802              fp3 = floatx80_add(fp3, float64_to_floatx80(make_float64(
803                                 0x3FC5555555554018), status),
804                                 status); /* fp3 is A2+S*A4 */
805              fp2 = floatx80_mul(fp2, fp1, status); /* fp2 is S*(A3+S*A5) */
806              fp3 = floatx80_mul(fp3, fp1, status); /* fp3 is S*(A2+S*A4) */
807              fp2 = floatx80_add(fp2, float32_to_floatx80(
808                                 make_float32(0x3F000000), status),
809                                 status); /* fp2 is A1+S*(A3+S*A5) */
810              fp3 = floatx80_mul(fp3, fp0, status); /* fp3 IS R*S*(A2+S*A4) */
811              fp2 = floatx80_mul(fp2, fp1,
812                                 status); /* fp2 IS S*(A1+S*(A3+S*A5)) */
813              fp0 = floatx80_add(fp0, fp3, status); /* fp0 IS R+R*S*(A2+S*A4) */
814              fp0 = floatx80_add(fp0, fp2, status); /* fp0 IS EXP(R) - 1 */
815  
816              fp1 = exp_tbl[j];
817              fp0 = floatx80_mul(fp0, fp1, status); /* 2^(J/64)*(Exp(R)-1) */
818              fp0 = floatx80_add(fp0, float32_to_floatx80(exp_tbl2[j], status),
819                                 status); /* accurate 2^(J/64) */
820              fp0 = floatx80_add(fp0, fp1,
821                                 status); /* 2^(J/64) + 2^(J/64)*(Exp(R)-1) */
822  
823              scale = packFloatx80(0, m, one_sig);
824              if (adjflag) {
825                  adjscale = packFloatx80(0, m1, one_sig);
826                  fp0 = floatx80_mul(fp0, adjscale, status);
827              }
828  
829              status->float_rounding_mode = user_rnd_mode;
830              status->floatx80_rounding_precision = user_rnd_prec;
831  
832              a = floatx80_mul(fp0, scale, status);
833  
834              float_raise(float_flag_inexact, status);
835  
836              return a;
837          } else { /* |X| >= 16380 log2 */
838              if (compact > 0x400CB27C) { /* |X| >= 16480 log2 */
839                  status->float_rounding_mode = user_rnd_mode;
840                  status->floatx80_rounding_precision = user_rnd_prec;
841                  if (aSign) {
842                      a = roundAndPackFloatx80(
843                                             status->floatx80_rounding_precision,
844                                             0, -0x1000, aSig, 0, status);
845                  } else {
846                      a = roundAndPackFloatx80(
847                                             status->floatx80_rounding_precision,
848                                             0, 0x8000, aSig, 0, status);
849                  }
850                  float_raise(float_flag_inexact, status);
851  
852                  return a;
853              } else {
854                  fp0 = a;
855                  fp1 = a;
856                  fp0 = floatx80_mul(fp0, float32_to_floatx80(
857                                     make_float32(0x42B8AA3B), status),
858                                     status); /* 64/log2 * X */
859                  adjflag = 1;
860                  n = floatx80_to_int32(fp0, status); /* int(64/log2*X) */
861                  fp0 = int32_to_floatx80(n, status);
862  
863                  j = n & 0x3F; /* J = N mod 64 */
864                  /* NOTE: this is really arithmetic right shift by 6 */
865                  k = n / 64;
866                  if (n < 0 && j) {
867                      /* arithmetic right shift is division and
868                       * round towards minus infinity
869                       */
870                      k--;
871                  }
872                  /* NOTE: this is really arithmetic right shift by 1 */
873                  m1 = k / 2;
874                  if (k < 0 && (k & 1)) {
875                      /* arithmetic right shift is division and
876                       * round towards minus infinity
877                       */
878                      m1--;
879                  }
880                  m = k - m1;
881                  m1 += 0x3FFF; /* biased exponent of 2^(M1) */
882                  m += 0x3FFF; /* biased exponent of 2^(M) */
883  
884                  goto expcont1;
885              }
886          }
887      } else { /* |X| < 2^(-65) */
888          status->float_rounding_mode = user_rnd_mode;
889          status->floatx80_rounding_precision = user_rnd_prec;
890  
891          a = floatx80_add(a, float32_to_floatx80(make_float32(0x3F800000),
892                           status), status); /* 1 + X */
893  
894          float_raise(float_flag_inexact, status);
895  
896          return a;
897      }
898  }
899  
900  /*
901   * 2 to x
902   */
903  
904  floatx80 floatx80_twotox(floatx80 a, float_status *status)
905  {
906      bool aSign;
907      int32_t aExp;
908      uint64_t aSig;
909  
910      FloatRoundMode user_rnd_mode;
911      FloatX80RoundPrec user_rnd_prec;
912  
913      int32_t compact, n, j, l, m, m1;
914      floatx80 fp0, fp1, fp2, fp3, adjfact, fact1, fact2;
915  
916      aSig = extractFloatx80Frac(a);
917      aExp = extractFloatx80Exp(a);
918      aSign = extractFloatx80Sign(a);
919  
920      if (aExp == 0x7FFF) {
921          if ((uint64_t) (aSig << 1)) {
922              return propagateFloatx80NaNOneArg(a, status);
923          }
924          if (aSign) {
925              return packFloatx80(0, 0, 0);
926          }
927          return packFloatx80(0, floatx80_infinity.high,
928                              floatx80_infinity.low);
929      }
930  
931      if (aExp == 0 && aSig == 0) {
932          return packFloatx80(0, one_exp, one_sig);
933      }
934  
935      user_rnd_mode = status->float_rounding_mode;
936      user_rnd_prec = status->floatx80_rounding_precision;
937      status->float_rounding_mode = float_round_nearest_even;
938      status->floatx80_rounding_precision = floatx80_precision_x;
939  
940      fp0 = a;
941  
942      compact = floatx80_make_compact(aExp, aSig);
943  
944      if (compact < 0x3FB98000 || compact > 0x400D80C0) {
945          /* |X| > 16480 or |X| < 2^(-70) */
946          if (compact > 0x3FFF8000) { /* |X| > 16480 */
947              status->float_rounding_mode = user_rnd_mode;
948              status->floatx80_rounding_precision = user_rnd_prec;
949  
950              if (aSign) {
951                  return roundAndPackFloatx80(status->floatx80_rounding_precision,
952                                              0, -0x1000, aSig, 0, status);
953              } else {
954                  return roundAndPackFloatx80(status->floatx80_rounding_precision,
955                                              0, 0x8000, aSig, 0, status);
956              }
957          } else { /* |X| < 2^(-70) */
958              status->float_rounding_mode = user_rnd_mode;
959              status->floatx80_rounding_precision = user_rnd_prec;
960  
961              a = floatx80_add(fp0, float32_to_floatx80(
962                               make_float32(0x3F800000), status),
963                               status); /* 1 + X */
964  
965              float_raise(float_flag_inexact, status);
966  
967              return a;
968          }
969      } else { /* 2^(-70) <= |X| <= 16480 */
970          fp1 = fp0; /* X */
971          fp1 = floatx80_mul(fp1, float32_to_floatx80(
972                             make_float32(0x42800000), status),
973                             status); /* X * 64 */
974          n = floatx80_to_int32(fp1, status);
975          fp1 = int32_to_floatx80(n, status);
976          j = n & 0x3F;
977          l = n / 64; /* NOTE: this is really arithmetic right shift by 6 */
978          if (n < 0 && j) {
979              /*
980               * arithmetic right shift is division and
981               * round towards minus infinity
982               */
983              l--;
984          }
985          m = l / 2; /* NOTE: this is really arithmetic right shift by 1 */
986          if (l < 0 && (l & 1)) {
987              /*
988               * arithmetic right shift is division and
989               * round towards minus infinity
990               */
991              m--;
992          }
993          m1 = l - m;
994          m1 += 0x3FFF; /* ADJFACT IS 2^(M') */
995  
996          adjfact = packFloatx80(0, m1, one_sig);
997          fact1 = exp2_tbl[j];
998          fact1.high += m;
999          fact2.high = exp2_tbl2[j] >> 16;
1000          fact2.high += m;
1001          fact2.low = (uint64_t)(exp2_tbl2[j] & 0xFFFF);
1002          fact2.low <<= 48;
1003  
1004          fp1 = floatx80_mul(fp1, float32_to_floatx80(
1005                             make_float32(0x3C800000), status),
1006                             status); /* (1/64)*N */
1007          fp0 = floatx80_sub(fp0, fp1, status); /* X - (1/64)*INT(64 X) */
1008          fp2 = packFloatx80(0, 0x3FFE, UINT64_C(0xB17217F7D1CF79AC)); /* LOG2 */
1009          fp0 = floatx80_mul(fp0, fp2, status); /* R */
1010  
1011          /* EXPR */
1012          fp1 = floatx80_mul(fp0, fp0, status); /* S = R*R */
1013          fp2 = float64_to_floatx80(make_float64(0x3F56C16D6F7BD0B2),
1014                                    status); /* A5 */
1015          fp3 = float64_to_floatx80(make_float64(0x3F811112302C712C),
1016                                    status); /* A4 */
1017          fp2 = floatx80_mul(fp2, fp1, status); /* S*A5 */
1018          fp3 = floatx80_mul(fp3, fp1, status); /* S*A4 */
1019          fp2 = floatx80_add(fp2, float64_to_floatx80(
1020                             make_float64(0x3FA5555555554CC1), status),
1021                             status); /* A3+S*A5 */
1022          fp3 = floatx80_add(fp3, float64_to_floatx80(
1023                             make_float64(0x3FC5555555554A54), status),
1024                             status); /* A2+S*A4 */
1025          fp2 = floatx80_mul(fp2, fp1, status); /* S*(A3+S*A5) */
1026          fp3 = floatx80_mul(fp3, fp1, status); /* S*(A2+S*A4) */
1027          fp2 = floatx80_add(fp2, float64_to_floatx80(
1028                             make_float64(0x3FE0000000000000), status),
1029                             status); /* A1+S*(A3+S*A5) */
1030          fp3 = floatx80_mul(fp3, fp0, status); /* R*S*(A2+S*A4) */
1031  
1032          fp2 = floatx80_mul(fp2, fp1, status); /* S*(A1+S*(A3+S*A5)) */
1033          fp0 = floatx80_add(fp0, fp3, status); /* R+R*S*(A2+S*A4) */
1034          fp0 = floatx80_add(fp0, fp2, status); /* EXP(R) - 1 */
1035  
1036          fp0 = floatx80_mul(fp0, fact1, status);
1037          fp0 = floatx80_add(fp0, fact2, status);
1038          fp0 = floatx80_add(fp0, fact1, status);
1039  
1040          status->float_rounding_mode = user_rnd_mode;
1041          status->floatx80_rounding_precision = user_rnd_prec;
1042  
1043          a = floatx80_mul(fp0, adjfact, status);
1044  
1045          float_raise(float_flag_inexact, status);
1046  
1047          return a;
1048      }
1049  }
1050  
1051  /*
1052   * 10 to x
1053   */
1054  
1055  floatx80 floatx80_tentox(floatx80 a, float_status *status)
1056  {
1057      bool aSign;
1058      int32_t aExp;
1059      uint64_t aSig;
1060  
1061      FloatRoundMode user_rnd_mode;
1062      FloatX80RoundPrec user_rnd_prec;
1063  
1064      int32_t compact, n, j, l, m, m1;
1065      floatx80 fp0, fp1, fp2, fp3, adjfact, fact1, fact2;
1066  
1067      aSig = extractFloatx80Frac(a);
1068      aExp = extractFloatx80Exp(a);
1069      aSign = extractFloatx80Sign(a);
1070  
1071      if (aExp == 0x7FFF) {
1072          if ((uint64_t) (aSig << 1)) {
1073              return propagateFloatx80NaNOneArg(a, status);
1074          }
1075          if (aSign) {
1076              return packFloatx80(0, 0, 0);
1077          }
1078          return packFloatx80(0, floatx80_infinity.high,
1079                              floatx80_infinity.low);
1080      }
1081  
1082      if (aExp == 0 && aSig == 0) {
1083          return packFloatx80(0, one_exp, one_sig);
1084      }
1085  
1086      user_rnd_mode = status->float_rounding_mode;
1087      user_rnd_prec = status->floatx80_rounding_precision;
1088      status->float_rounding_mode = float_round_nearest_even;
1089      status->floatx80_rounding_precision = floatx80_precision_x;
1090  
1091      fp0 = a;
1092  
1093      compact = floatx80_make_compact(aExp, aSig);
1094  
1095      if (compact < 0x3FB98000 || compact > 0x400B9B07) {
1096          /* |X| > 16480 LOG2/LOG10 or |X| < 2^(-70) */
1097          if (compact > 0x3FFF8000) { /* |X| > 16480 */
1098              status->float_rounding_mode = user_rnd_mode;
1099              status->floatx80_rounding_precision = user_rnd_prec;
1100  
1101              if (aSign) {
1102                  return roundAndPackFloatx80(status->floatx80_rounding_precision,
1103                                              0, -0x1000, aSig, 0, status);
1104              } else {
1105                  return roundAndPackFloatx80(status->floatx80_rounding_precision,
1106                                              0, 0x8000, aSig, 0, status);
1107              }
1108          } else { /* |X| < 2^(-70) */
1109              status->float_rounding_mode = user_rnd_mode;
1110              status->floatx80_rounding_precision = user_rnd_prec;
1111  
1112              a = floatx80_add(fp0, float32_to_floatx80(
1113                               make_float32(0x3F800000), status),
1114                               status); /* 1 + X */
1115  
1116              float_raise(float_flag_inexact, status);
1117  
1118              return a;
1119          }
1120      } else { /* 2^(-70) <= |X| <= 16480 LOG 2 / LOG 10 */
1121          fp1 = fp0; /* X */
1122          fp1 = floatx80_mul(fp1, float64_to_floatx80(
1123                             make_float64(0x406A934F0979A371),
1124                             status), status); /* X*64*LOG10/LOG2 */
1125          n = floatx80_to_int32(fp1, status); /* N=INT(X*64*LOG10/LOG2) */
1126          fp1 = int32_to_floatx80(n, status);
1127  
1128          j = n & 0x3F;
1129          l = n / 64; /* NOTE: this is really arithmetic right shift by 6 */
1130          if (n < 0 && j) {
1131              /*
1132               * arithmetic right shift is division and
1133               * round towards minus infinity
1134               */
1135              l--;
1136          }
1137          m = l / 2; /* NOTE: this is really arithmetic right shift by 1 */
1138          if (l < 0 && (l & 1)) {
1139              /*
1140               * arithmetic right shift is division and
1141               * round towards minus infinity
1142               */
1143              m--;
1144          }
1145          m1 = l - m;
1146          m1 += 0x3FFF; /* ADJFACT IS 2^(M') */
1147  
1148          adjfact = packFloatx80(0, m1, one_sig);
1149          fact1 = exp2_tbl[j];
1150          fact1.high += m;
1151          fact2.high = exp2_tbl2[j] >> 16;
1152          fact2.high += m;
1153          fact2.low = (uint64_t)(exp2_tbl2[j] & 0xFFFF);
1154          fact2.low <<= 48;
1155  
1156          fp2 = fp1; /* N */
1157          fp1 = floatx80_mul(fp1, float64_to_floatx80(
1158                             make_float64(0x3F734413509F8000), status),
1159                             status); /* N*(LOG2/64LOG10)_LEAD */
1160          fp3 = packFloatx80(1, 0x3FCD, UINT64_C(0xC0219DC1DA994FD2));
1161          fp2 = floatx80_mul(fp2, fp3, status); /* N*(LOG2/64LOG10)_TRAIL */
1162          fp0 = floatx80_sub(fp0, fp1, status); /* X - N L_LEAD */
1163          fp0 = floatx80_sub(fp0, fp2, status); /* X - N L_TRAIL */
1164          fp2 = packFloatx80(0, 0x4000, UINT64_C(0x935D8DDDAAA8AC17)); /* LOG10 */
1165          fp0 = floatx80_mul(fp0, fp2, status); /* R */
1166  
1167          /* EXPR */
1168          fp1 = floatx80_mul(fp0, fp0, status); /* S = R*R */
1169          fp2 = float64_to_floatx80(make_float64(0x3F56C16D6F7BD0B2),
1170                                    status); /* A5 */
1171          fp3 = float64_to_floatx80(make_float64(0x3F811112302C712C),
1172                                    status); /* A4 */
1173          fp2 = floatx80_mul(fp2, fp1, status); /* S*A5 */
1174          fp3 = floatx80_mul(fp3, fp1, status); /* S*A4 */
1175          fp2 = floatx80_add(fp2, float64_to_floatx80(
1176                             make_float64(0x3FA5555555554CC1), status),
1177                             status); /* A3+S*A5 */
1178          fp3 = floatx80_add(fp3, float64_to_floatx80(
1179                             make_float64(0x3FC5555555554A54), status),
1180                             status); /* A2+S*A4 */
1181          fp2 = floatx80_mul(fp2, fp1, status); /* S*(A3+S*A5) */
1182          fp3 = floatx80_mul(fp3, fp1, status); /* S*(A2+S*A4) */
1183          fp2 = floatx80_add(fp2, float64_to_floatx80(
1184                             make_float64(0x3FE0000000000000), status),
1185                             status); /* A1+S*(A3+S*A5) */
1186          fp3 = floatx80_mul(fp3, fp0, status); /* R*S*(A2+S*A4) */
1187  
1188          fp2 = floatx80_mul(fp2, fp1, status); /* S*(A1+S*(A3+S*A5)) */
1189          fp0 = floatx80_add(fp0, fp3, status); /* R+R*S*(A2+S*A4) */
1190          fp0 = floatx80_add(fp0, fp2, status); /* EXP(R) - 1 */
1191  
1192          fp0 = floatx80_mul(fp0, fact1, status);
1193          fp0 = floatx80_add(fp0, fact2, status);
1194          fp0 = floatx80_add(fp0, fact1, status);
1195  
1196          status->float_rounding_mode = user_rnd_mode;
1197          status->floatx80_rounding_precision = user_rnd_prec;
1198  
1199          a = floatx80_mul(fp0, adjfact, status);
1200  
1201          float_raise(float_flag_inexact, status);
1202  
1203          return a;
1204      }
1205  }
1206  
1207  /*
1208   * Tangent
1209   */
1210  
1211  floatx80 floatx80_tan(floatx80 a, float_status *status)
1212  {
1213      bool aSign, xSign;
1214      int32_t aExp, xExp;
1215      uint64_t aSig, xSig;
1216  
1217      FloatRoundMode user_rnd_mode;
1218      FloatX80RoundPrec user_rnd_prec;
1219  
1220      int32_t compact, l, n, j;
1221      floatx80 fp0, fp1, fp2, fp3, fp4, fp5, invtwopi, twopi1, twopi2;
1222      float32 twoto63;
1223      bool endflag;
1224  
1225      aSig = extractFloatx80Frac(a);
1226      aExp = extractFloatx80Exp(a);
1227      aSign = extractFloatx80Sign(a);
1228  
1229      if (aExp == 0x7FFF) {
1230          if ((uint64_t) (aSig << 1)) {
1231              return propagateFloatx80NaNOneArg(a, status);
1232          }
1233          float_raise(float_flag_invalid, status);
1234          return floatx80_default_nan(status);
1235      }
1236  
1237      if (aExp == 0 && aSig == 0) {
1238          return packFloatx80(aSign, 0, 0);
1239      }
1240  
1241      user_rnd_mode = status->float_rounding_mode;
1242      user_rnd_prec = status->floatx80_rounding_precision;
1243      status->float_rounding_mode = float_round_nearest_even;
1244      status->floatx80_rounding_precision = floatx80_precision_x;
1245  
1246      compact = floatx80_make_compact(aExp, aSig);
1247  
1248      fp0 = a;
1249  
1250      if (compact < 0x3FD78000 || compact > 0x4004BC7E) {
1251          /* 2^(-40) > |X| > 15 PI */
1252          if (compact > 0x3FFF8000) { /* |X| >= 15 PI */
1253              /* REDUCEX */
1254              fp1 = packFloatx80(0, 0, 0);
1255              if (compact == 0x7FFEFFFF) {
1256                  twopi1 = packFloatx80(aSign ^ 1, 0x7FFE,
1257                                        UINT64_C(0xC90FDAA200000000));
1258                  twopi2 = packFloatx80(aSign ^ 1, 0x7FDC,
1259                                        UINT64_C(0x85A308D300000000));
1260                  fp0 = floatx80_add(fp0, twopi1, status);
1261                  fp1 = fp0;
1262                  fp0 = floatx80_add(fp0, twopi2, status);
1263                  fp1 = floatx80_sub(fp1, fp0, status);
1264                  fp1 = floatx80_add(fp1, twopi2, status);
1265              }
1266          loop:
1267              xSign = extractFloatx80Sign(fp0);
1268              xExp = extractFloatx80Exp(fp0);
1269              xExp -= 0x3FFF;
1270              if (xExp <= 28) {
1271                  l = 0;
1272                  endflag = true;
1273              } else {
1274                  l = xExp - 27;
1275                  endflag = false;
1276              }
1277              invtwopi = packFloatx80(0, 0x3FFE - l,
1278                                      UINT64_C(0xA2F9836E4E44152A)); /* INVTWOPI */
1279              twopi1 = packFloatx80(0, 0x3FFF + l, UINT64_C(0xC90FDAA200000000));
1280              twopi2 = packFloatx80(0, 0x3FDD + l, UINT64_C(0x85A308D300000000));
1281  
1282              /* SIGN(INARG)*2^63 IN SGL */
1283              twoto63 = packFloat32(xSign, 0xBE, 0);
1284  
1285              fp2 = floatx80_mul(fp0, invtwopi, status);
1286              fp2 = floatx80_add(fp2, float32_to_floatx80(twoto63, status),
1287                                 status); /* THE FRACT PART OF FP2 IS ROUNDED */
1288              fp2 = floatx80_sub(fp2, float32_to_floatx80(twoto63, status),
1289                                 status); /* FP2 is N */
1290              fp4 = floatx80_mul(twopi1, fp2, status); /* W = N*P1 */
1291              fp5 = floatx80_mul(twopi2, fp2, status); /* w = N*P2 */
1292              fp3 = floatx80_add(fp4, fp5, status); /* FP3 is P */
1293              fp4 = floatx80_sub(fp4, fp3, status); /* W-P */
1294              fp0 = floatx80_sub(fp0, fp3, status); /* FP0 is A := R - P */
1295              fp4 = floatx80_add(fp4, fp5, status); /* FP4 is p = (W-P)+w */
1296              fp3 = fp0; /* FP3 is A */
1297              fp1 = floatx80_sub(fp1, fp4, status); /* FP1 is a := r - p */
1298              fp0 = floatx80_add(fp0, fp1, status); /* FP0 is R := A+a */
1299  
1300              if (endflag) {
1301                  n = floatx80_to_int32(fp2, status);
1302                  goto tancont;
1303              }
1304              fp3 = floatx80_sub(fp3, fp0, status); /* A-R */
1305              fp1 = floatx80_add(fp1, fp3, status); /* FP1 is r := (A-R)+a */
1306              goto loop;
1307          } else {
1308              status->float_rounding_mode = user_rnd_mode;
1309              status->floatx80_rounding_precision = user_rnd_prec;
1310  
1311              a = floatx80_move(a, status);
1312  
1313              float_raise(float_flag_inexact, status);
1314  
1315              return a;
1316          }
1317      } else {
1318          fp1 = floatx80_mul(fp0, float64_to_floatx80(
1319                             make_float64(0x3FE45F306DC9C883), status),
1320                             status); /* X*2/PI */
1321  
1322          n = floatx80_to_int32(fp1, status);
1323          j = 32 + n;
1324  
1325          fp0 = floatx80_sub(fp0, pi_tbl[j], status); /* X-Y1 */
1326          fp0 = floatx80_sub(fp0, float32_to_floatx80(pi_tbl2[j], status),
1327                             status); /* FP0 IS R = (X-Y1)-Y2 */
1328  
1329      tancont:
1330          if (n & 1) {
1331              /* NODD */
1332              fp1 = fp0; /* R */
1333              fp0 = floatx80_mul(fp0, fp0, status); /* S = R*R */
1334              fp3 = float64_to_floatx80(make_float64(0x3EA0B759F50F8688),
1335                                        status); /* Q4 */
1336              fp2 = float64_to_floatx80(make_float64(0xBEF2BAA5A8924F04),
1337                                        status); /* P3 */
1338              fp3 = floatx80_mul(fp3, fp0, status); /* SQ4 */
1339              fp2 = floatx80_mul(fp2, fp0, status); /* SP3 */
1340              fp3 = floatx80_add(fp3, float64_to_floatx80(
1341                                 make_float64(0xBF346F59B39BA65F), status),
1342                                 status); /* Q3+SQ4 */
1343              fp4 = packFloatx80(0, 0x3FF6, UINT64_C(0xE073D3FC199C4A00));
1344              fp2 = floatx80_add(fp2, fp4, status); /* P2+SP3 */
1345              fp3 = floatx80_mul(fp3, fp0, status); /* S(Q3+SQ4) */
1346              fp2 = floatx80_mul(fp2, fp0, status); /* S(P2+SP3) */
1347              fp4 = packFloatx80(0, 0x3FF9, UINT64_C(0xD23CD68415D95FA1));
1348              fp3 = floatx80_add(fp3, fp4, status); /* Q2+S(Q3+SQ4) */
1349              fp4 = packFloatx80(1, 0x3FFC, UINT64_C(0x8895A6C5FB423BCA));
1350              fp2 = floatx80_add(fp2, fp4, status); /* P1+S(P2+SP3) */
1351              fp3 = floatx80_mul(fp3, fp0, status); /* S(Q2+S(Q3+SQ4)) */
1352              fp2 = floatx80_mul(fp2, fp0, status); /* S(P1+S(P2+SP3)) */
1353              fp4 = packFloatx80(1, 0x3FFD, UINT64_C(0xEEF57E0DA84BC8CE));
1354              fp3 = floatx80_add(fp3, fp4, status); /* Q1+S(Q2+S(Q3+SQ4)) */
1355              fp2 = floatx80_mul(fp2, fp1, status); /* RS(P1+S(P2+SP3)) */
1356              fp0 = floatx80_mul(fp0, fp3, status); /* S(Q1+S(Q2+S(Q3+SQ4))) */
1357              fp1 = floatx80_add(fp1, fp2, status); /* R+RS(P1+S(P2+SP3)) */
1358              fp0 = floatx80_add(fp0, float32_to_floatx80(
1359                                 make_float32(0x3F800000), status),
1360                                 status); /* 1+S(Q1+S(Q2+S(Q3+SQ4))) */
1361  
1362              xSign = extractFloatx80Sign(fp1);
1363              xExp = extractFloatx80Exp(fp1);
1364              xSig = extractFloatx80Frac(fp1);
1365              xSign ^= 1;
1366              fp1 = packFloatx80(xSign, xExp, xSig);
1367  
1368              status->float_rounding_mode = user_rnd_mode;
1369              status->floatx80_rounding_precision = user_rnd_prec;
1370  
1371              a = floatx80_div(fp0, fp1, status);
1372  
1373              float_raise(float_flag_inexact, status);
1374  
1375              return a;
1376          } else {
1377              fp1 = floatx80_mul(fp0, fp0, status); /* S = R*R */
1378              fp3 = float64_to_floatx80(make_float64(0x3EA0B759F50F8688),
1379                                        status); /* Q4 */
1380              fp2 = float64_to_floatx80(make_float64(0xBEF2BAA5A8924F04),
1381                                        status); /* P3 */
1382              fp3 = floatx80_mul(fp3, fp1, status); /* SQ4 */
1383              fp2 = floatx80_mul(fp2, fp1, status); /* SP3 */
1384              fp3 = floatx80_add(fp3, float64_to_floatx80(
1385                                 make_float64(0xBF346F59B39BA65F), status),
1386                                 status); /* Q3+SQ4 */
1387              fp4 = packFloatx80(0, 0x3FF6, UINT64_C(0xE073D3FC199C4A00));
1388              fp2 = floatx80_add(fp2, fp4, status); /* P2+SP3 */
1389              fp3 = floatx80_mul(fp3, fp1, status); /* S(Q3+SQ4) */
1390              fp2 = floatx80_mul(fp2, fp1, status); /* S(P2+SP3) */
1391              fp4 = packFloatx80(0, 0x3FF9, UINT64_C(0xD23CD68415D95FA1));
1392              fp3 = floatx80_add(fp3, fp4, status); /* Q2+S(Q3+SQ4) */
1393              fp4 = packFloatx80(1, 0x3FFC, UINT64_C(0x8895A6C5FB423BCA));
1394              fp2 = floatx80_add(fp2, fp4, status); /* P1+S(P2+SP3) */
1395              fp3 = floatx80_mul(fp3, fp1, status); /* S(Q2+S(Q3+SQ4)) */
1396              fp2 = floatx80_mul(fp2, fp1, status); /* S(P1+S(P2+SP3)) */
1397              fp4 = packFloatx80(1, 0x3FFD, UINT64_C(0xEEF57E0DA84BC8CE));
1398              fp3 = floatx80_add(fp3, fp4, status); /* Q1+S(Q2+S(Q3+SQ4)) */
1399              fp2 = floatx80_mul(fp2, fp0, status); /* RS(P1+S(P2+SP3)) */
1400              fp1 = floatx80_mul(fp1, fp3, status); /* S(Q1+S(Q2+S(Q3+SQ4))) */
1401              fp0 = floatx80_add(fp0, fp2, status); /* R+RS(P1+S(P2+SP3)) */
1402              fp1 = floatx80_add(fp1, float32_to_floatx80(
1403                                 make_float32(0x3F800000), status),
1404                                 status); /* 1+S(Q1+S(Q2+S(Q3+SQ4))) */
1405  
1406              status->float_rounding_mode = user_rnd_mode;
1407              status->floatx80_rounding_precision = user_rnd_prec;
1408  
1409              a = floatx80_div(fp0, fp1, status);
1410  
1411              float_raise(float_flag_inexact, status);
1412  
1413              return a;
1414          }
1415      }
1416  }
1417  
1418  /*
1419   * Sine
1420   */
1421  
1422  floatx80 floatx80_sin(floatx80 a, float_status *status)
1423  {
1424      bool aSign, xSign;
1425      int32_t aExp, xExp;
1426      uint64_t aSig, xSig;
1427  
1428      FloatRoundMode user_rnd_mode;
1429      FloatX80RoundPrec user_rnd_prec;
1430  
1431      int32_t compact, l, n, j;
1432      floatx80 fp0, fp1, fp2, fp3, fp4, fp5, x, invtwopi, twopi1, twopi2;
1433      float32 posneg1, twoto63;
1434      bool endflag;
1435  
1436      aSig = extractFloatx80Frac(a);
1437      aExp = extractFloatx80Exp(a);
1438      aSign = extractFloatx80Sign(a);
1439  
1440      if (aExp == 0x7FFF) {
1441          if ((uint64_t) (aSig << 1)) {
1442              return propagateFloatx80NaNOneArg(a, status);
1443          }
1444          float_raise(float_flag_invalid, status);
1445          return floatx80_default_nan(status);
1446      }
1447  
1448      if (aExp == 0 && aSig == 0) {
1449          return packFloatx80(aSign, 0, 0);
1450      }
1451  
1452      user_rnd_mode = status->float_rounding_mode;
1453      user_rnd_prec = status->floatx80_rounding_precision;
1454      status->float_rounding_mode = float_round_nearest_even;
1455      status->floatx80_rounding_precision = floatx80_precision_x;
1456  
1457      compact = floatx80_make_compact(aExp, aSig);
1458  
1459      fp0 = a;
1460  
1461      if (compact < 0x3FD78000 || compact > 0x4004BC7E) {
1462          /* 2^(-40) > |X| > 15 PI */
1463          if (compact > 0x3FFF8000) { /* |X| >= 15 PI */
1464              /* REDUCEX */
1465              fp1 = packFloatx80(0, 0, 0);
1466              if (compact == 0x7FFEFFFF) {
1467                  twopi1 = packFloatx80(aSign ^ 1, 0x7FFE,
1468                                        UINT64_C(0xC90FDAA200000000));
1469                  twopi2 = packFloatx80(aSign ^ 1, 0x7FDC,
1470                                        UINT64_C(0x85A308D300000000));
1471                  fp0 = floatx80_add(fp0, twopi1, status);
1472                  fp1 = fp0;
1473                  fp0 = floatx80_add(fp0, twopi2, status);
1474                  fp1 = floatx80_sub(fp1, fp0, status);
1475                  fp1 = floatx80_add(fp1, twopi2, status);
1476              }
1477          loop:
1478              xSign = extractFloatx80Sign(fp0);
1479              xExp = extractFloatx80Exp(fp0);
1480              xExp -= 0x3FFF;
1481              if (xExp <= 28) {
1482                  l = 0;
1483                  endflag = true;
1484              } else {
1485                  l = xExp - 27;
1486                  endflag = false;
1487              }
1488              invtwopi = packFloatx80(0, 0x3FFE - l,
1489                                      UINT64_C(0xA2F9836E4E44152A)); /* INVTWOPI */
1490              twopi1 = packFloatx80(0, 0x3FFF + l, UINT64_C(0xC90FDAA200000000));
1491              twopi2 = packFloatx80(0, 0x3FDD + l, UINT64_C(0x85A308D300000000));
1492  
1493              /* SIGN(INARG)*2^63 IN SGL */
1494              twoto63 = packFloat32(xSign, 0xBE, 0);
1495  
1496              fp2 = floatx80_mul(fp0, invtwopi, status);
1497              fp2 = floatx80_add(fp2, float32_to_floatx80(twoto63, status),
1498                                 status); /* THE FRACT PART OF FP2 IS ROUNDED */
1499              fp2 = floatx80_sub(fp2, float32_to_floatx80(twoto63, status),
1500                                 status); /* FP2 is N */
1501              fp4 = floatx80_mul(twopi1, fp2, status); /* W = N*P1 */
1502              fp5 = floatx80_mul(twopi2, fp2, status); /* w = N*P2 */
1503              fp3 = floatx80_add(fp4, fp5, status); /* FP3 is P */
1504              fp4 = floatx80_sub(fp4, fp3, status); /* W-P */
1505              fp0 = floatx80_sub(fp0, fp3, status); /* FP0 is A := R - P */
1506              fp4 = floatx80_add(fp4, fp5, status); /* FP4 is p = (W-P)+w */
1507              fp3 = fp0; /* FP3 is A */
1508              fp1 = floatx80_sub(fp1, fp4, status); /* FP1 is a := r - p */
1509              fp0 = floatx80_add(fp0, fp1, status); /* FP0 is R := A+a */
1510  
1511              if (endflag) {
1512                  n = floatx80_to_int32(fp2, status);
1513                  goto sincont;
1514              }
1515              fp3 = floatx80_sub(fp3, fp0, status); /* A-R */
1516              fp1 = floatx80_add(fp1, fp3, status); /* FP1 is r := (A-R)+a */
1517              goto loop;
1518          } else {
1519              /* SINSM */
1520              fp0 = float32_to_floatx80(make_float32(0x3F800000),
1521                                        status); /* 1 */
1522  
1523              status->float_rounding_mode = user_rnd_mode;
1524              status->floatx80_rounding_precision = user_rnd_prec;
1525  
1526              /* SINTINY */
1527              a = floatx80_move(a, status);
1528              float_raise(float_flag_inexact, status);
1529  
1530              return a;
1531          }
1532      } else {
1533          fp1 = floatx80_mul(fp0, float64_to_floatx80(
1534                             make_float64(0x3FE45F306DC9C883), status),
1535                             status); /* X*2/PI */
1536  
1537          n = floatx80_to_int32(fp1, status);
1538          j = 32 + n;
1539  
1540          fp0 = floatx80_sub(fp0, pi_tbl[j], status); /* X-Y1 */
1541          fp0 = floatx80_sub(fp0, float32_to_floatx80(pi_tbl2[j], status),
1542                             status); /* FP0 IS R = (X-Y1)-Y2 */
1543  
1544      sincont:
1545          if (n & 1) {
1546              /* COSPOLY */
1547              fp0 = floatx80_mul(fp0, fp0, status); /* FP0 IS S */
1548              fp1 = floatx80_mul(fp0, fp0, status); /* FP1 IS T */
1549              fp2 = float64_to_floatx80(make_float64(0x3D2AC4D0D6011EE3),
1550                                        status); /* B8 */
1551              fp3 = float64_to_floatx80(make_float64(0xBDA9396F9F45AC19),
1552                                        status); /* B7 */
1553  
1554              xSign = extractFloatx80Sign(fp0); /* X IS S */
1555              xExp = extractFloatx80Exp(fp0);
1556              xSig = extractFloatx80Frac(fp0);
1557  
1558              if ((n >> 1) & 1) {
1559                  xSign ^= 1;
1560                  posneg1 = make_float32(0xBF800000); /* -1 */
1561              } else {
1562                  xSign ^= 0;
1563                  posneg1 = make_float32(0x3F800000); /* 1 */
1564              } /* X IS NOW R'= SGN*R */
1565  
1566              fp2 = floatx80_mul(fp2, fp1, status); /* TB8 */
1567              fp3 = floatx80_mul(fp3, fp1, status); /* TB7 */
1568              fp2 = floatx80_add(fp2, float64_to_floatx80(
1569                                 make_float64(0x3E21EED90612C972), status),
1570                                 status); /* B6+TB8 */
1571              fp3 = floatx80_add(fp3, float64_to_floatx80(
1572                                 make_float64(0xBE927E4FB79D9FCF), status),
1573                                 status); /* B5+TB7 */
1574              fp2 = floatx80_mul(fp2, fp1, status); /* T(B6+TB8) */
1575              fp3 = floatx80_mul(fp3, fp1, status); /* T(B5+TB7) */
1576              fp2 = floatx80_add(fp2, float64_to_floatx80(
1577                                 make_float64(0x3EFA01A01A01D423), status),
1578                                 status); /* B4+T(B6+TB8) */
1579              fp4 = packFloatx80(1, 0x3FF5, UINT64_C(0xB60B60B60B61D438));
1580              fp3 = floatx80_add(fp3, fp4, status); /* B3+T(B5+TB7) */
1581              fp2 = floatx80_mul(fp2, fp1, status); /* T(B4+T(B6+TB8)) */
1582              fp1 = floatx80_mul(fp1, fp3, status); /* T(B3+T(B5+TB7)) */
1583              fp4 = packFloatx80(0, 0x3FFA, UINT64_C(0xAAAAAAAAAAAAAB5E));
1584              fp2 = floatx80_add(fp2, fp4, status); /* B2+T(B4+T(B6+TB8)) */
1585              fp1 = floatx80_add(fp1, float32_to_floatx80(
1586                                 make_float32(0xBF000000), status),
1587                                 status); /* B1+T(B3+T(B5+TB7)) */
1588              fp0 = floatx80_mul(fp0, fp2, status); /* S(B2+T(B4+T(B6+TB8))) */
1589              fp0 = floatx80_add(fp0, fp1, status); /* [B1+T(B3+T(B5+TB7))]+
1590                                                     * [S(B2+T(B4+T(B6+TB8)))]
1591                                                     */
1592  
1593              x = packFloatx80(xSign, xExp, xSig);
1594              fp0 = floatx80_mul(fp0, x, status);
1595  
1596              status->float_rounding_mode = user_rnd_mode;
1597              status->floatx80_rounding_precision = user_rnd_prec;
1598  
1599              a = floatx80_add(fp0, float32_to_floatx80(posneg1, status), status);
1600  
1601              float_raise(float_flag_inexact, status);
1602  
1603              return a;
1604          } else {
1605              /* SINPOLY */
1606              xSign = extractFloatx80Sign(fp0); /* X IS R */
1607              xExp = extractFloatx80Exp(fp0);
1608              xSig = extractFloatx80Frac(fp0);
1609  
1610              xSign ^= (n >> 1) & 1; /* X IS NOW R'= SGN*R */
1611  
1612              fp0 = floatx80_mul(fp0, fp0, status); /* FP0 IS S */
1613              fp1 = floatx80_mul(fp0, fp0, status); /* FP1 IS T */
1614              fp3 = float64_to_floatx80(make_float64(0xBD6AAA77CCC994F5),
1615                                        status); /* A7 */
1616              fp2 = float64_to_floatx80(make_float64(0x3DE612097AAE8DA1),
1617                                        status); /* A6 */
1618              fp3 = floatx80_mul(fp3, fp1, status); /* T*A7 */
1619              fp2 = floatx80_mul(fp2, fp1, status); /* T*A6 */
1620              fp3 = floatx80_add(fp3, float64_to_floatx80(
1621                                 make_float64(0xBE5AE6452A118AE4), status),
1622                                 status); /* A5+T*A7 */
1623              fp2 = floatx80_add(fp2, float64_to_floatx80(
1624                                 make_float64(0x3EC71DE3A5341531), status),
1625                                 status); /* A4+T*A6 */
1626              fp3 = floatx80_mul(fp3, fp1, status); /* T(A5+TA7) */
1627              fp2 = floatx80_mul(fp2, fp1, status); /* T(A4+TA6) */
1628              fp3 = floatx80_add(fp3, float64_to_floatx80(
1629                                 make_float64(0xBF2A01A01A018B59), status),
1630                                 status); /* A3+T(A5+TA7) */
1631              fp4 = packFloatx80(0, 0x3FF8, UINT64_C(0x88888888888859AF));
1632              fp2 = floatx80_add(fp2, fp4, status); /* A2+T(A4+TA6) */
1633              fp1 = floatx80_mul(fp1, fp3, status); /* T(A3+T(A5+TA7)) */
1634              fp2 = floatx80_mul(fp2, fp0, status); /* S(A2+T(A4+TA6)) */
1635              fp4 = packFloatx80(1, 0x3FFC, UINT64_C(0xAAAAAAAAAAAAAA99));
1636              fp1 = floatx80_add(fp1, fp4, status); /* A1+T(A3+T(A5+TA7)) */
1637              fp1 = floatx80_add(fp1, fp2,
1638                                 status); /* [A1+T(A3+T(A5+TA7))]+
1639                                           * [S(A2+T(A4+TA6))]
1640                                           */
1641  
1642              x = packFloatx80(xSign, xExp, xSig);
1643              fp0 = floatx80_mul(fp0, x, status); /* R'*S */
1644              fp0 = floatx80_mul(fp0, fp1, status); /* SIN(R')-R' */
1645  
1646              status->float_rounding_mode = user_rnd_mode;
1647              status->floatx80_rounding_precision = user_rnd_prec;
1648  
1649              a = floatx80_add(fp0, x, status);
1650  
1651              float_raise(float_flag_inexact, status);
1652  
1653              return a;
1654          }
1655      }
1656  }
1657  
1658  /*
1659   * Cosine
1660   */
1661  
1662  floatx80 floatx80_cos(floatx80 a, float_status *status)
1663  {
1664      bool aSign, xSign;
1665      int32_t aExp, xExp;
1666      uint64_t aSig, xSig;
1667  
1668      FloatRoundMode user_rnd_mode;
1669      FloatX80RoundPrec user_rnd_prec;
1670  
1671      int32_t compact, l, n, j;
1672      floatx80 fp0, fp1, fp2, fp3, fp4, fp5, x, invtwopi, twopi1, twopi2;
1673      float32 posneg1, twoto63;
1674      bool endflag;
1675  
1676      aSig = extractFloatx80Frac(a);
1677      aExp = extractFloatx80Exp(a);
1678      aSign = extractFloatx80Sign(a);
1679  
1680      if (aExp == 0x7FFF) {
1681          if ((uint64_t) (aSig << 1)) {
1682              return propagateFloatx80NaNOneArg(a, status);
1683          }
1684          float_raise(float_flag_invalid, status);
1685          return floatx80_default_nan(status);
1686      }
1687  
1688      if (aExp == 0 && aSig == 0) {
1689          return packFloatx80(0, one_exp, one_sig);
1690      }
1691  
1692      user_rnd_mode = status->float_rounding_mode;
1693      user_rnd_prec = status->floatx80_rounding_precision;
1694      status->float_rounding_mode = float_round_nearest_even;
1695      status->floatx80_rounding_precision = floatx80_precision_x;
1696  
1697      compact = floatx80_make_compact(aExp, aSig);
1698  
1699      fp0 = a;
1700  
1701      if (compact < 0x3FD78000 || compact > 0x4004BC7E) {
1702          /* 2^(-40) > |X| > 15 PI */
1703          if (compact > 0x3FFF8000) { /* |X| >= 15 PI */
1704              /* REDUCEX */
1705              fp1 = packFloatx80(0, 0, 0);
1706              if (compact == 0x7FFEFFFF) {
1707                  twopi1 = packFloatx80(aSign ^ 1, 0x7FFE,
1708                                        UINT64_C(0xC90FDAA200000000));
1709                  twopi2 = packFloatx80(aSign ^ 1, 0x7FDC,
1710                                        UINT64_C(0x85A308D300000000));
1711                  fp0 = floatx80_add(fp0, twopi1, status);
1712                  fp1 = fp0;
1713                  fp0 = floatx80_add(fp0, twopi2, status);
1714                  fp1 = floatx80_sub(fp1, fp0, status);
1715                  fp1 = floatx80_add(fp1, twopi2, status);
1716              }
1717          loop:
1718              xSign = extractFloatx80Sign(fp0);
1719              xExp = extractFloatx80Exp(fp0);
1720              xExp -= 0x3FFF;
1721              if (xExp <= 28) {
1722                  l = 0;
1723                  endflag = true;
1724              } else {
1725                  l = xExp - 27;
1726                  endflag = false;
1727              }
1728              invtwopi = packFloatx80(0, 0x3FFE - l,
1729                                      UINT64_C(0xA2F9836E4E44152A)); /* INVTWOPI */
1730              twopi1 = packFloatx80(0, 0x3FFF + l, UINT64_C(0xC90FDAA200000000));
1731              twopi2 = packFloatx80(0, 0x3FDD + l, UINT64_C(0x85A308D300000000));
1732  
1733              /* SIGN(INARG)*2^63 IN SGL */
1734              twoto63 = packFloat32(xSign, 0xBE, 0);
1735  
1736              fp2 = floatx80_mul(fp0, invtwopi, status);
1737              fp2 = floatx80_add(fp2, float32_to_floatx80(twoto63, status),
1738                                 status); /* THE FRACT PART OF FP2 IS ROUNDED */
1739              fp2 = floatx80_sub(fp2, float32_to_floatx80(twoto63, status),
1740                                 status); /* FP2 is N */
1741              fp4 = floatx80_mul(twopi1, fp2, status); /* W = N*P1 */
1742              fp5 = floatx80_mul(twopi2, fp2, status); /* w = N*P2 */
1743              fp3 = floatx80_add(fp4, fp5, status); /* FP3 is P */
1744              fp4 = floatx80_sub(fp4, fp3, status); /* W-P */
1745              fp0 = floatx80_sub(fp0, fp3, status); /* FP0 is A := R - P */
1746              fp4 = floatx80_add(fp4, fp5, status); /* FP4 is p = (W-P)+w */
1747              fp3 = fp0; /* FP3 is A */
1748              fp1 = floatx80_sub(fp1, fp4, status); /* FP1 is a := r - p */
1749              fp0 = floatx80_add(fp0, fp1, status); /* FP0 is R := A+a */
1750  
1751              if (endflag) {
1752                  n = floatx80_to_int32(fp2, status);
1753                  goto sincont;
1754              }
1755              fp3 = floatx80_sub(fp3, fp0, status); /* A-R */
1756              fp1 = floatx80_add(fp1, fp3, status); /* FP1 is r := (A-R)+a */
1757              goto loop;
1758          } else {
1759              /* SINSM */
1760              fp0 = float32_to_floatx80(make_float32(0x3F800000), status); /* 1 */
1761  
1762              status->float_rounding_mode = user_rnd_mode;
1763              status->floatx80_rounding_precision = user_rnd_prec;
1764  
1765              /* COSTINY */
1766              a = floatx80_sub(fp0, float32_to_floatx80(
1767                               make_float32(0x00800000), status),
1768                               status);
1769              float_raise(float_flag_inexact, status);
1770  
1771              return a;
1772          }
1773      } else {
1774          fp1 = floatx80_mul(fp0, float64_to_floatx80(
1775                             make_float64(0x3FE45F306DC9C883), status),
1776                             status); /* X*2/PI */
1777  
1778          n = floatx80_to_int32(fp1, status);
1779          j = 32 + n;
1780  
1781          fp0 = floatx80_sub(fp0, pi_tbl[j], status); /* X-Y1 */
1782          fp0 = floatx80_sub(fp0, float32_to_floatx80(pi_tbl2[j], status),
1783                             status); /* FP0 IS R = (X-Y1)-Y2 */
1784  
1785      sincont:
1786          if ((n + 1) & 1) {
1787              /* COSPOLY */
1788              fp0 = floatx80_mul(fp0, fp0, status); /* FP0 IS S */
1789              fp1 = floatx80_mul(fp0, fp0, status); /* FP1 IS T */
1790              fp2 = float64_to_floatx80(make_float64(0x3D2AC4D0D6011EE3),
1791                                        status); /* B8 */
1792              fp3 = float64_to_floatx80(make_float64(0xBDA9396F9F45AC19),
1793                                        status); /* B7 */
1794  
1795              xSign = extractFloatx80Sign(fp0); /* X IS S */
1796              xExp = extractFloatx80Exp(fp0);
1797              xSig = extractFloatx80Frac(fp0);
1798  
1799              if (((n + 1) >> 1) & 1) {
1800                  xSign ^= 1;
1801                  posneg1 = make_float32(0xBF800000); /* -1 */
1802              } else {
1803                  xSign ^= 0;
1804                  posneg1 = make_float32(0x3F800000); /* 1 */
1805              } /* X IS NOW R'= SGN*R */
1806  
1807              fp2 = floatx80_mul(fp2, fp1, status); /* TB8 */
1808              fp3 = floatx80_mul(fp3, fp1, status); /* TB7 */
1809              fp2 = floatx80_add(fp2, float64_to_floatx80(
1810                                 make_float64(0x3E21EED90612C972), status),
1811                                 status); /* B6+TB8 */
1812              fp3 = floatx80_add(fp3, float64_to_floatx80(
1813                                 make_float64(0xBE927E4FB79D9FCF), status),
1814                                 status); /* B5+TB7 */
1815              fp2 = floatx80_mul(fp2, fp1, status); /* T(B6+TB8) */
1816              fp3 = floatx80_mul(fp3, fp1, status); /* T(B5+TB7) */
1817              fp2 = floatx80_add(fp2, float64_to_floatx80(
1818                                 make_float64(0x3EFA01A01A01D423), status),
1819                                 status); /* B4+T(B6+TB8) */
1820              fp4 = packFloatx80(1, 0x3FF5, UINT64_C(0xB60B60B60B61D438));
1821              fp3 = floatx80_add(fp3, fp4, status); /* B3+T(B5+TB7) */
1822              fp2 = floatx80_mul(fp2, fp1, status); /* T(B4+T(B6+TB8)) */
1823              fp1 = floatx80_mul(fp1, fp3, status); /* T(B3+T(B5+TB7)) */
1824              fp4 = packFloatx80(0, 0x3FFA, UINT64_C(0xAAAAAAAAAAAAAB5E));
1825              fp2 = floatx80_add(fp2, fp4, status); /* B2+T(B4+T(B6+TB8)) */
1826              fp1 = floatx80_add(fp1, float32_to_floatx80(
1827                                 make_float32(0xBF000000), status),
1828                                 status); /* B1+T(B3+T(B5+TB7)) */
1829              fp0 = floatx80_mul(fp0, fp2, status); /* S(B2+T(B4+T(B6+TB8))) */
1830              fp0 = floatx80_add(fp0, fp1, status);
1831                                /* [B1+T(B3+T(B5+TB7))]+[S(B2+T(B4+T(B6+TB8)))] */
1832  
1833              x = packFloatx80(xSign, xExp, xSig);
1834              fp0 = floatx80_mul(fp0, x, status);
1835  
1836              status->float_rounding_mode = user_rnd_mode;
1837              status->floatx80_rounding_precision = user_rnd_prec;
1838  
1839              a = floatx80_add(fp0, float32_to_floatx80(posneg1, status), status);
1840  
1841              float_raise(float_flag_inexact, status);
1842  
1843              return a;
1844          } else {
1845              /* SINPOLY */
1846              xSign = extractFloatx80Sign(fp0); /* X IS R */
1847              xExp = extractFloatx80Exp(fp0);
1848              xSig = extractFloatx80Frac(fp0);
1849  
1850              xSign ^= ((n + 1) >> 1) & 1; /* X IS NOW R'= SGN*R */
1851  
1852              fp0 = floatx80_mul(fp0, fp0, status); /* FP0 IS S */
1853              fp1 = floatx80_mul(fp0, fp0, status); /* FP1 IS T */
1854              fp3 = float64_to_floatx80(make_float64(0xBD6AAA77CCC994F5),
1855                                        status); /* A7 */
1856              fp2 = float64_to_floatx80(make_float64(0x3DE612097AAE8DA1),
1857                                        status); /* A6 */
1858              fp3 = floatx80_mul(fp3, fp1, status); /* T*A7 */
1859              fp2 = floatx80_mul(fp2, fp1, status); /* T*A6 */
1860              fp3 = floatx80_add(fp3, float64_to_floatx80(
1861                                 make_float64(0xBE5AE6452A118AE4), status),
1862                                 status); /* A5+T*A7 */
1863              fp2 = floatx80_add(fp2, float64_to_floatx80(
1864                                 make_float64(0x3EC71DE3A5341531), status),
1865                                 status); /* A4+T*A6 */
1866              fp3 = floatx80_mul(fp3, fp1, status); /* T(A5+TA7) */
1867              fp2 = floatx80_mul(fp2, fp1, status); /* T(A4+TA6) */
1868              fp3 = floatx80_add(fp3, float64_to_floatx80(
1869                                 make_float64(0xBF2A01A01A018B59), status),
1870                                 status); /* A3+T(A5+TA7) */
1871              fp4 = packFloatx80(0, 0x3FF8, UINT64_C(0x88888888888859AF));
1872              fp2 = floatx80_add(fp2, fp4, status); /* A2+T(A4+TA6) */
1873              fp1 = floatx80_mul(fp1, fp3, status); /* T(A3+T(A5+TA7)) */
1874              fp2 = floatx80_mul(fp2, fp0, status); /* S(A2+T(A4+TA6)) */
1875              fp4 = packFloatx80(1, 0x3FFC, UINT64_C(0xAAAAAAAAAAAAAA99));
1876              fp1 = floatx80_add(fp1, fp4, status); /* A1+T(A3+T(A5+TA7)) */
1877              fp1 = floatx80_add(fp1, fp2, status);
1878                                      /* [A1+T(A3+T(A5+TA7))]+[S(A2+T(A4+TA6))] */
1879  
1880              x = packFloatx80(xSign, xExp, xSig);
1881              fp0 = floatx80_mul(fp0, x, status); /* R'*S */
1882              fp0 = floatx80_mul(fp0, fp1, status); /* SIN(R')-R' */
1883  
1884              status->float_rounding_mode = user_rnd_mode;
1885              status->floatx80_rounding_precision = user_rnd_prec;
1886  
1887              a = floatx80_add(fp0, x, status);
1888  
1889              float_raise(float_flag_inexact, status);
1890  
1891              return a;
1892          }
1893      }
1894  }
1895  
1896  /*
1897   * Arc tangent
1898   */
1899  
1900  floatx80 floatx80_atan(floatx80 a, float_status *status)
1901  {
1902      bool aSign;
1903      int32_t aExp;
1904      uint64_t aSig;
1905  
1906      FloatRoundMode user_rnd_mode;
1907      FloatX80RoundPrec user_rnd_prec;
1908  
1909      int32_t compact, tbl_index;
1910      floatx80 fp0, fp1, fp2, fp3, xsave;
1911  
1912      aSig = extractFloatx80Frac(a);
1913      aExp = extractFloatx80Exp(a);
1914      aSign = extractFloatx80Sign(a);
1915  
1916      if (aExp == 0x7FFF) {
1917          if ((uint64_t) (aSig << 1)) {
1918              return propagateFloatx80NaNOneArg(a, status);
1919          }
1920          a = packFloatx80(aSign, piby2_exp, pi_sig);
1921          float_raise(float_flag_inexact, status);
1922          return floatx80_move(a, status);
1923      }
1924  
1925      if (aExp == 0 && aSig == 0) {
1926          return packFloatx80(aSign, 0, 0);
1927      }
1928  
1929      compact = floatx80_make_compact(aExp, aSig);
1930  
1931      user_rnd_mode = status->float_rounding_mode;
1932      user_rnd_prec = status->floatx80_rounding_precision;
1933      status->float_rounding_mode = float_round_nearest_even;
1934      status->floatx80_rounding_precision = floatx80_precision_x;
1935  
1936      if (compact < 0x3FFB8000 || compact > 0x4002FFFF) {
1937          /* |X| >= 16 or |X| < 1/16 */
1938          if (compact > 0x3FFF8000) { /* |X| >= 16 */
1939              if (compact > 0x40638000) { /* |X| > 2^(100) */
1940                  fp0 = packFloatx80(aSign, piby2_exp, pi_sig);
1941                  fp1 = packFloatx80(aSign, 0x0001, one_sig);
1942  
1943                  status->float_rounding_mode = user_rnd_mode;
1944                  status->floatx80_rounding_precision = user_rnd_prec;
1945  
1946                  a = floatx80_sub(fp0, fp1, status);
1947  
1948                  float_raise(float_flag_inexact, status);
1949  
1950                  return a;
1951              } else {
1952                  fp0 = a;
1953                  fp1 = packFloatx80(1, one_exp, one_sig); /* -1 */
1954                  fp1 = floatx80_div(fp1, fp0, status); /* X' = -1/X */
1955                  xsave = fp1;
1956                  fp0 = floatx80_mul(fp1, fp1, status); /* Y = X'*X' */
1957                  fp1 = floatx80_mul(fp0, fp0, status); /* Z = Y*Y */
1958                  fp3 = float64_to_floatx80(make_float64(0xBFB70BF398539E6A),
1959                                            status); /* C5 */
1960                  fp2 = float64_to_floatx80(make_float64(0x3FBC7187962D1D7D),
1961                                            status); /* C4 */
1962                  fp3 = floatx80_mul(fp3, fp1, status); /* Z*C5 */
1963                  fp2 = floatx80_mul(fp2, fp1, status); /* Z*C4 */
1964                  fp3 = floatx80_add(fp3, float64_to_floatx80(
1965                                     make_float64(0xBFC24924827107B8), status),
1966                                     status); /* C3+Z*C5 */
1967                  fp2 = floatx80_add(fp2, float64_to_floatx80(
1968                                     make_float64(0x3FC999999996263E), status),
1969                                     status); /* C2+Z*C4 */
1970                  fp1 = floatx80_mul(fp1, fp3, status); /* Z*(C3+Z*C5) */
1971                  fp2 = floatx80_mul(fp2, fp0, status); /* Y*(C2+Z*C4) */
1972                  fp1 = floatx80_add(fp1, float64_to_floatx80(
1973                                     make_float64(0xBFD5555555555536), status),
1974                                     status); /* C1+Z*(C3+Z*C5) */
1975                  fp0 = floatx80_mul(fp0, xsave, status); /* X'*Y */
1976                  /* [Y*(C2+Z*C4)]+[C1+Z*(C3+Z*C5)] */
1977                  fp1 = floatx80_add(fp1, fp2, status);
1978                  /* X'*Y*([B1+Z*(B3+Z*B5)]+[Y*(B2+Z*(B4+Z*B6))]) ?? */
1979                  fp0 = floatx80_mul(fp0, fp1, status);
1980                  fp0 = floatx80_add(fp0, xsave, status);
1981                  fp1 = packFloatx80(aSign, piby2_exp, pi_sig);
1982  
1983                  status->float_rounding_mode = user_rnd_mode;
1984                  status->floatx80_rounding_precision = user_rnd_prec;
1985  
1986                  a = floatx80_add(fp0, fp1, status);
1987  
1988                  float_raise(float_flag_inexact, status);
1989  
1990                  return a;
1991              }
1992          } else { /* |X| < 1/16 */
1993              if (compact < 0x3FD78000) { /* |X| < 2^(-40) */
1994                  status->float_rounding_mode = user_rnd_mode;
1995                  status->floatx80_rounding_precision = user_rnd_prec;
1996  
1997                  a = floatx80_move(a, status);
1998  
1999                  float_raise(float_flag_inexact, status);
2000  
2001                  return a;
2002              } else {
2003                  fp0 = a;
2004                  xsave = a;
2005                  fp0 = floatx80_mul(fp0, fp0, status); /* Y = X*X */
2006                  fp1 = floatx80_mul(fp0, fp0, status); /* Z = Y*Y */
2007                  fp2 = float64_to_floatx80(make_float64(0x3FB344447F876989),
2008                                            status); /* B6 */
2009                  fp3 = float64_to_floatx80(make_float64(0xBFB744EE7FAF45DB),
2010                                            status); /* B5 */
2011                  fp2 = floatx80_mul(fp2, fp1, status); /* Z*B6 */
2012                  fp3 = floatx80_mul(fp3, fp1, status); /* Z*B5 */
2013                  fp2 = floatx80_add(fp2, float64_to_floatx80(
2014                                     make_float64(0x3FBC71C646940220), status),
2015                                     status); /* B4+Z*B6 */
2016                  fp3 = floatx80_add(fp3, float64_to_floatx80(
2017                                     make_float64(0xBFC24924921872F9),
2018                                     status), status); /* B3+Z*B5 */
2019                  fp2 = floatx80_mul(fp2, fp1, status); /* Z*(B4+Z*B6) */
2020                  fp1 = floatx80_mul(fp1, fp3, status); /* Z*(B3+Z*B5) */
2021                  fp2 = floatx80_add(fp2, float64_to_floatx80(
2022                                     make_float64(0x3FC9999999998FA9), status),
2023                                     status); /* B2+Z*(B4+Z*B6) */
2024                  fp1 = floatx80_add(fp1, float64_to_floatx80(
2025                                     make_float64(0xBFD5555555555555), status),
2026                                     status); /* B1+Z*(B3+Z*B5) */
2027                  fp2 = floatx80_mul(fp2, fp0, status); /* Y*(B2+Z*(B4+Z*B6)) */
2028                  fp0 = floatx80_mul(fp0, xsave, status); /* X*Y */
2029                  /* [B1+Z*(B3+Z*B5)]+[Y*(B2+Z*(B4+Z*B6))] */
2030                  fp1 = floatx80_add(fp1, fp2, status);
2031                  /* X*Y*([B1+Z*(B3+Z*B5)]+[Y*(B2+Z*(B4+Z*B6))]) */
2032                  fp0 = floatx80_mul(fp0, fp1, status);
2033  
2034                  status->float_rounding_mode = user_rnd_mode;
2035                  status->floatx80_rounding_precision = user_rnd_prec;
2036  
2037                  a = floatx80_add(fp0, xsave, status);
2038  
2039                  float_raise(float_flag_inexact, status);
2040  
2041                  return a;
2042              }
2043          }
2044      } else {
2045          aSig &= UINT64_C(0xF800000000000000);
2046          aSig |= UINT64_C(0x0400000000000000);
2047          xsave = packFloatx80(aSign, aExp, aSig); /* F */
2048          fp0 = a;
2049          fp1 = a; /* X */
2050          fp2 = packFloatx80(0, one_exp, one_sig); /* 1 */
2051          fp1 = floatx80_mul(fp1, xsave, status); /* X*F */
2052          fp0 = floatx80_sub(fp0, xsave, status); /* X-F */
2053          fp1 = floatx80_add(fp1, fp2, status); /* 1 + X*F */
2054          fp0 = floatx80_div(fp0, fp1, status); /* U = (X-F)/(1+X*F) */
2055  
2056          tbl_index = compact;
2057  
2058          tbl_index &= 0x7FFF0000;
2059          tbl_index -= 0x3FFB0000;
2060          tbl_index >>= 1;
2061          tbl_index += compact & 0x00007800;
2062          tbl_index >>= 11;
2063  
2064          fp3 = atan_tbl[tbl_index];
2065  
2066          fp3.high |= aSign ? 0x8000 : 0; /* ATAN(F) */
2067  
2068          fp1 = floatx80_mul(fp0, fp0, status); /* V = U*U */
2069          fp2 = float64_to_floatx80(make_float64(0xBFF6687E314987D8),
2070                                    status); /* A3 */
2071          fp2 = floatx80_add(fp2, fp1, status); /* A3+V */
2072          fp2 = floatx80_mul(fp2, fp1, status); /* V*(A3+V) */
2073          fp1 = floatx80_mul(fp1, fp0, status); /* U*V */
2074          fp2 = floatx80_add(fp2, float64_to_floatx80(
2075                             make_float64(0x4002AC6934A26DB3), status),
2076                             status); /* A2+V*(A3+V) */
2077          fp1 = floatx80_mul(fp1, float64_to_floatx80(
2078                             make_float64(0xBFC2476F4E1DA28E), status),
2079                             status); /* A1+U*V */
2080          fp1 = floatx80_mul(fp1, fp2, status); /* A1*U*V*(A2+V*(A3+V)) */
2081          fp0 = floatx80_add(fp0, fp1, status); /* ATAN(U) */
2082  
2083          status->float_rounding_mode = user_rnd_mode;
2084          status->floatx80_rounding_precision = user_rnd_prec;
2085  
2086          a = floatx80_add(fp0, fp3, status); /* ATAN(X) */
2087  
2088          float_raise(float_flag_inexact, status);
2089  
2090          return a;
2091      }
2092  }
2093  
2094  /*
2095   * Arc sine
2096   */
2097  
2098  floatx80 floatx80_asin(floatx80 a, float_status *status)
2099  {
2100      bool aSign;
2101      int32_t aExp;
2102      uint64_t aSig;
2103  
2104      FloatRoundMode user_rnd_mode;
2105      FloatX80RoundPrec user_rnd_prec;
2106  
2107      int32_t compact;
2108      floatx80 fp0, fp1, fp2, one;
2109  
2110      aSig = extractFloatx80Frac(a);
2111      aExp = extractFloatx80Exp(a);
2112      aSign = extractFloatx80Sign(a);
2113  
2114      if (aExp == 0x7FFF && (uint64_t) (aSig << 1)) {
2115          return propagateFloatx80NaNOneArg(a, status);
2116      }
2117  
2118      if (aExp == 0 && aSig == 0) {
2119          return packFloatx80(aSign, 0, 0);
2120      }
2121  
2122      compact = floatx80_make_compact(aExp, aSig);
2123  
2124      if (compact >= 0x3FFF8000) { /* |X| >= 1 */
2125          if (aExp == one_exp && aSig == one_sig) { /* |X| == 1 */
2126              float_raise(float_flag_inexact, status);
2127              a = packFloatx80(aSign, piby2_exp, pi_sig);
2128              return floatx80_move(a, status);
2129          } else { /* |X| > 1 */
2130              float_raise(float_flag_invalid, status);
2131              return floatx80_default_nan(status);
2132          }
2133  
2134      } /* |X| < 1 */
2135  
2136      user_rnd_mode = status->float_rounding_mode;
2137      user_rnd_prec = status->floatx80_rounding_precision;
2138      status->float_rounding_mode = float_round_nearest_even;
2139      status->floatx80_rounding_precision = floatx80_precision_x;
2140  
2141      one = packFloatx80(0, one_exp, one_sig);
2142      fp0 = a;
2143  
2144      fp1 = floatx80_sub(one, fp0, status);   /* 1 - X */
2145      fp2 = floatx80_add(one, fp0, status);   /* 1 + X */
2146      fp1 = floatx80_mul(fp2, fp1, status);   /* (1+X)*(1-X) */
2147      fp1 = floatx80_sqrt(fp1, status);       /* SQRT((1+X)*(1-X)) */
2148      fp0 = floatx80_div(fp0, fp1, status);   /* X/SQRT((1+X)*(1-X)) */
2149  
2150      status->float_rounding_mode = user_rnd_mode;
2151      status->floatx80_rounding_precision = user_rnd_prec;
2152  
2153      a = floatx80_atan(fp0, status);         /* ATAN(X/SQRT((1+X)*(1-X))) */
2154  
2155      float_raise(float_flag_inexact, status);
2156  
2157      return a;
2158  }
2159  
2160  /*
2161   * Arc cosine
2162   */
2163  
2164  floatx80 floatx80_acos(floatx80 a, float_status *status)
2165  {
2166      bool aSign;
2167      int32_t aExp;
2168      uint64_t aSig;
2169  
2170      FloatRoundMode user_rnd_mode;
2171      FloatX80RoundPrec user_rnd_prec;
2172  
2173      int32_t compact;
2174      floatx80 fp0, fp1, one;
2175  
2176      aSig = extractFloatx80Frac(a);
2177      aExp = extractFloatx80Exp(a);
2178      aSign = extractFloatx80Sign(a);
2179  
2180      if (aExp == 0x7FFF && (uint64_t) (aSig << 1)) {
2181          return propagateFloatx80NaNOneArg(a, status);
2182      }
2183      if (aExp == 0 && aSig == 0) {
2184          float_raise(float_flag_inexact, status);
2185          return roundAndPackFloatx80(status->floatx80_rounding_precision, 0,
2186                                      piby2_exp, pi_sig, 0, status);
2187      }
2188  
2189      compact = floatx80_make_compact(aExp, aSig);
2190  
2191      if (compact >= 0x3FFF8000) { /* |X| >= 1 */
2192          if (aExp == one_exp && aSig == one_sig) { /* |X| == 1 */
2193              if (aSign) { /* X == -1 */
2194                  a = packFloatx80(0, pi_exp, pi_sig);
2195                  float_raise(float_flag_inexact, status);
2196                  return floatx80_move(a, status);
2197              } else { /* X == +1 */
2198                  return packFloatx80(0, 0, 0);
2199              }
2200          } else { /* |X| > 1 */
2201              float_raise(float_flag_invalid, status);
2202              return floatx80_default_nan(status);
2203          }
2204      } /* |X| < 1 */
2205  
2206      user_rnd_mode = status->float_rounding_mode;
2207      user_rnd_prec = status->floatx80_rounding_precision;
2208      status->float_rounding_mode = float_round_nearest_even;
2209      status->floatx80_rounding_precision = floatx80_precision_x;
2210  
2211      one = packFloatx80(0, one_exp, one_sig);
2212      fp0 = a;
2213  
2214      fp1 = floatx80_add(one, fp0, status);   /* 1 + X */
2215      fp0 = floatx80_sub(one, fp0, status);   /* 1 - X */
2216      fp0 = floatx80_div(fp0, fp1, status);   /* (1-X)/(1+X) */
2217      fp0 = floatx80_sqrt(fp0, status);       /* SQRT((1-X)/(1+X)) */
2218      fp0 = floatx80_atan(fp0, status);       /* ATAN(SQRT((1-X)/(1+X))) */
2219  
2220      status->float_rounding_mode = user_rnd_mode;
2221      status->floatx80_rounding_precision = user_rnd_prec;
2222  
2223      a = floatx80_add(fp0, fp0, status);     /* 2 * ATAN(SQRT((1-X)/(1+X))) */
2224  
2225      float_raise(float_flag_inexact, status);
2226  
2227      return a;
2228  }
2229  
2230  /*
2231   * Hyperbolic arc tangent
2232   */
2233  
2234  floatx80 floatx80_atanh(floatx80 a, float_status *status)
2235  {
2236      bool aSign;
2237      int32_t aExp;
2238      uint64_t aSig;
2239  
2240      FloatRoundMode user_rnd_mode;
2241      FloatX80RoundPrec user_rnd_prec;
2242  
2243      int32_t compact;
2244      floatx80 fp0, fp1, fp2, one;
2245  
2246      aSig = extractFloatx80Frac(a);
2247      aExp = extractFloatx80Exp(a);
2248      aSign = extractFloatx80Sign(a);
2249  
2250      if (aExp == 0x7FFF && (uint64_t) (aSig << 1)) {
2251          return propagateFloatx80NaNOneArg(a, status);
2252      }
2253  
2254      if (aExp == 0 && aSig == 0) {
2255          return packFloatx80(aSign, 0, 0);
2256      }
2257  
2258      compact = floatx80_make_compact(aExp, aSig);
2259  
2260      if (compact >= 0x3FFF8000) { /* |X| >= 1 */
2261          if (aExp == one_exp && aSig == one_sig) { /* |X| == 1 */
2262              float_raise(float_flag_divbyzero, status);
2263              return packFloatx80(aSign, floatx80_infinity.high,
2264                                  floatx80_infinity.low);
2265          } else { /* |X| > 1 */
2266              float_raise(float_flag_invalid, status);
2267              return floatx80_default_nan(status);
2268          }
2269      } /* |X| < 1 */
2270  
2271      user_rnd_mode = status->float_rounding_mode;
2272      user_rnd_prec = status->floatx80_rounding_precision;
2273      status->float_rounding_mode = float_round_nearest_even;
2274      status->floatx80_rounding_precision = floatx80_precision_x;
2275  
2276      one = packFloatx80(0, one_exp, one_sig);
2277      fp2 = packFloatx80(aSign, 0x3FFE, one_sig); /* SIGN(X) * (1/2) */
2278      fp0 = packFloatx80(0, aExp, aSig); /* Y = |X| */
2279      fp1 = packFloatx80(1, aExp, aSig); /* -Y */
2280      fp0 = floatx80_add(fp0, fp0, status); /* 2Y */
2281      fp1 = floatx80_add(fp1, one, status); /* 1-Y */
2282      fp0 = floatx80_div(fp0, fp1, status); /* Z = 2Y/(1-Y) */
2283      fp0 = floatx80_lognp1(fp0, status); /* LOG1P(Z) */
2284  
2285      status->float_rounding_mode = user_rnd_mode;
2286      status->floatx80_rounding_precision = user_rnd_prec;
2287  
2288      a = floatx80_mul(fp0, fp2,
2289                       status); /* ATANH(X) = SIGN(X) * (1/2) * LOG1P(Z) */
2290  
2291      float_raise(float_flag_inexact, status);
2292  
2293      return a;
2294  }
2295  
2296  /*
2297   * e to x minus 1
2298   */
2299  
2300  floatx80 floatx80_etoxm1(floatx80 a, float_status *status)
2301  {
2302      bool aSign;
2303      int32_t aExp;
2304      uint64_t aSig;
2305  
2306      FloatRoundMode user_rnd_mode;
2307      FloatX80RoundPrec user_rnd_prec;
2308  
2309      int32_t compact, n, j, m, m1;
2310      floatx80 fp0, fp1, fp2, fp3, l2, sc, onebysc;
2311  
2312      aSig = extractFloatx80Frac(a);
2313      aExp = extractFloatx80Exp(a);
2314      aSign = extractFloatx80Sign(a);
2315  
2316      if (aExp == 0x7FFF) {
2317          if ((uint64_t) (aSig << 1)) {
2318              return propagateFloatx80NaNOneArg(a, status);
2319          }
2320          if (aSign) {
2321              return packFloatx80(aSign, one_exp, one_sig);
2322          }
2323          return packFloatx80(0, floatx80_infinity.high,
2324                              floatx80_infinity.low);
2325      }
2326  
2327      if (aExp == 0 && aSig == 0) {
2328          return packFloatx80(aSign, 0, 0);
2329      }
2330  
2331      user_rnd_mode = status->float_rounding_mode;
2332      user_rnd_prec = status->floatx80_rounding_precision;
2333      status->float_rounding_mode = float_round_nearest_even;
2334      status->floatx80_rounding_precision = floatx80_precision_x;
2335  
2336      if (aExp >= 0x3FFD) { /* |X| >= 1/4 */
2337          compact = floatx80_make_compact(aExp, aSig);
2338  
2339          if (compact <= 0x4004C215) { /* |X| <= 70 log2 */
2340              fp0 = a;
2341              fp1 = a;
2342              fp0 = floatx80_mul(fp0, float32_to_floatx80(
2343                                 make_float32(0x42B8AA3B), status),
2344                                 status); /* 64/log2 * X */
2345              n = floatx80_to_int32(fp0, status); /* int(64/log2*X) */
2346              fp0 = int32_to_floatx80(n, status);
2347  
2348              j = n & 0x3F; /* J = N mod 64 */
2349              m = n / 64; /* NOTE: this is really arithmetic right shift by 6 */
2350              if (n < 0 && j) {
2351                  /*
2352                   * arithmetic right shift is division and
2353                   * round towards minus infinity
2354                   */
2355                  m--;
2356              }
2357              m1 = -m;
2358              /*m += 0x3FFF; // biased exponent of 2^(M) */
2359              /*m1 += 0x3FFF; // biased exponent of -2^(-M) */
2360  
2361              fp2 = fp0; /* N */
2362              fp0 = floatx80_mul(fp0, float32_to_floatx80(
2363                                 make_float32(0xBC317218), status),
2364                                 status); /* N * L1, L1 = lead(-log2/64) */
2365              l2 = packFloatx80(0, 0x3FDC, UINT64_C(0x82E308654361C4C6));
2366              fp2 = floatx80_mul(fp2, l2, status); /* N * L2, L1+L2 = -log2/64 */
2367              fp0 = floatx80_add(fp0, fp1, status); /* X + N*L1 */
2368              fp0 = floatx80_add(fp0, fp2, status); /* R */
2369  
2370              fp1 = floatx80_mul(fp0, fp0, status); /* S = R*R */
2371              fp2 = float32_to_floatx80(make_float32(0x3950097B),
2372                                        status); /* A6 */
2373              fp2 = floatx80_mul(fp2, fp1, status); /* fp2 is S*A6 */
2374              fp3 = floatx80_mul(float32_to_floatx80(make_float32(0x3AB60B6A),
2375                                 status), fp1, status); /* fp3 is S*A5 */
2376              fp2 = floatx80_add(fp2, float64_to_floatx80(
2377                                 make_float64(0x3F81111111174385), status),
2378                                 status); /* fp2 IS A4+S*A6 */
2379              fp3 = floatx80_add(fp3, float64_to_floatx80(
2380                                 make_float64(0x3FA5555555554F5A), status),
2381                                 status); /* fp3 is A3+S*A5 */
2382              fp2 = floatx80_mul(fp2, fp1, status); /* fp2 IS S*(A4+S*A6) */
2383              fp3 = floatx80_mul(fp3, fp1, status); /* fp3 IS S*(A3+S*A5) */
2384              fp2 = floatx80_add(fp2, float64_to_floatx80(
2385                                 make_float64(0x3FC5555555555555), status),
2386                                 status); /* fp2 IS A2+S*(A4+S*A6) */
2387              fp3 = floatx80_add(fp3, float32_to_floatx80(
2388                                 make_float32(0x3F000000), status),
2389                                 status); /* fp3 IS A1+S*(A3+S*A5) */
2390              fp2 = floatx80_mul(fp2, fp1,
2391                                 status); /* fp2 IS S*(A2+S*(A4+S*A6)) */
2392              fp1 = floatx80_mul(fp1, fp3,
2393                                 status); /* fp1 IS S*(A1+S*(A3+S*A5)) */
2394              fp2 = floatx80_mul(fp2, fp0,
2395                                 status); /* fp2 IS R*S*(A2+S*(A4+S*A6)) */
2396              fp0 = floatx80_add(fp0, fp1,
2397                                 status); /* fp0 IS R+S*(A1+S*(A3+S*A5)) */
2398              fp0 = floatx80_add(fp0, fp2, status); /* fp0 IS EXP(R) - 1 */
2399  
2400              fp0 = floatx80_mul(fp0, exp_tbl[j],
2401                                 status); /* 2^(J/64)*(Exp(R)-1) */
2402  
2403              if (m >= 64) {
2404                  fp1 = float32_to_floatx80(exp_tbl2[j], status);
2405                  onebysc = packFloatx80(1, m1 + 0x3FFF, one_sig); /* -2^(-M) */
2406                  fp1 = floatx80_add(fp1, onebysc, status);
2407                  fp0 = floatx80_add(fp0, fp1, status);
2408                  fp0 = floatx80_add(fp0, exp_tbl[j], status);
2409              } else if (m < -3) {
2410                  fp0 = floatx80_add(fp0, float32_to_floatx80(exp_tbl2[j],
2411                                     status), status);
2412                  fp0 = floatx80_add(fp0, exp_tbl[j], status);
2413                  onebysc = packFloatx80(1, m1 + 0x3FFF, one_sig); /* -2^(-M) */
2414                  fp0 = floatx80_add(fp0, onebysc, status);
2415              } else { /* -3 <= m <= 63 */
2416                  fp1 = exp_tbl[j];
2417                  fp0 = floatx80_add(fp0, float32_to_floatx80(exp_tbl2[j],
2418                                     status), status);
2419                  onebysc = packFloatx80(1, m1 + 0x3FFF, one_sig); /* -2^(-M) */
2420                  fp1 = floatx80_add(fp1, onebysc, status);
2421                  fp0 = floatx80_add(fp0, fp1, status);
2422              }
2423  
2424              sc = packFloatx80(0, m + 0x3FFF, one_sig);
2425  
2426              status->float_rounding_mode = user_rnd_mode;
2427              status->floatx80_rounding_precision = user_rnd_prec;
2428  
2429              a = floatx80_mul(fp0, sc, status);
2430  
2431              float_raise(float_flag_inexact, status);
2432  
2433              return a;
2434          } else { /* |X| > 70 log2 */
2435              if (aSign) {
2436                  fp0 = float32_to_floatx80(make_float32(0xBF800000),
2437                        status); /* -1 */
2438  
2439                  status->float_rounding_mode = user_rnd_mode;
2440                  status->floatx80_rounding_precision = user_rnd_prec;
2441  
2442                  a = floatx80_add(fp0, float32_to_floatx80(
2443                                   make_float32(0x00800000), status),
2444                                   status); /* -1 + 2^(-126) */
2445  
2446                  float_raise(float_flag_inexact, status);
2447  
2448                  return a;
2449              } else {
2450                  status->float_rounding_mode = user_rnd_mode;
2451                  status->floatx80_rounding_precision = user_rnd_prec;
2452  
2453                  return floatx80_etox(a, status);
2454              }
2455          }
2456      } else { /* |X| < 1/4 */
2457          if (aExp >= 0x3FBE) {
2458              fp0 = a;
2459              fp0 = floatx80_mul(fp0, fp0, status); /* S = X*X */
2460              fp1 = float32_to_floatx80(make_float32(0x2F30CAA8),
2461                                        status); /* B12 */
2462              fp1 = floatx80_mul(fp1, fp0, status); /* S * B12 */
2463              fp2 = float32_to_floatx80(make_float32(0x310F8290),
2464                                        status); /* B11 */
2465              fp1 = floatx80_add(fp1, float32_to_floatx80(
2466                                 make_float32(0x32D73220), status),
2467                                 status); /* B10 */
2468              fp2 = floatx80_mul(fp2, fp0, status);
2469              fp1 = floatx80_mul(fp1, fp0, status);
2470              fp2 = floatx80_add(fp2, float32_to_floatx80(
2471                                 make_float32(0x3493F281), status),
2472                                 status); /* B9 */
2473              fp1 = floatx80_add(fp1, float64_to_floatx80(
2474                                 make_float64(0x3EC71DE3A5774682), status),
2475                                 status); /* B8 */
2476              fp2 = floatx80_mul(fp2, fp0, status);
2477              fp1 = floatx80_mul(fp1, fp0, status);
2478              fp2 = floatx80_add(fp2, float64_to_floatx80(
2479                                 make_float64(0x3EFA01A019D7CB68), status),
2480                                 status); /* B7 */
2481              fp1 = floatx80_add(fp1, float64_to_floatx80(
2482                                 make_float64(0x3F2A01A01A019DF3), status),
2483                                 status); /* B6 */
2484              fp2 = floatx80_mul(fp2, fp0, status);
2485              fp1 = floatx80_mul(fp1, fp0, status);
2486              fp2 = floatx80_add(fp2, float64_to_floatx80(
2487                                 make_float64(0x3F56C16C16C170E2), status),
2488                                 status); /* B5 */
2489              fp1 = floatx80_add(fp1, float64_to_floatx80(
2490                                 make_float64(0x3F81111111111111), status),
2491                                 status); /* B4 */
2492              fp2 = floatx80_mul(fp2, fp0, status);
2493              fp1 = floatx80_mul(fp1, fp0, status);
2494              fp2 = floatx80_add(fp2, float64_to_floatx80(
2495                                 make_float64(0x3FA5555555555555), status),
2496                                 status); /* B3 */
2497              fp3 = packFloatx80(0, 0x3FFC, UINT64_C(0xAAAAAAAAAAAAAAAB));
2498              fp1 = floatx80_add(fp1, fp3, status); /* B2 */
2499              fp2 = floatx80_mul(fp2, fp0, status);
2500              fp1 = floatx80_mul(fp1, fp0, status);
2501  
2502              fp2 = floatx80_mul(fp2, fp0, status);
2503              fp1 = floatx80_mul(fp1, a, status);
2504  
2505              fp0 = floatx80_mul(fp0, float32_to_floatx80(
2506                                 make_float32(0x3F000000), status),
2507                                 status); /* S*B1 */
2508              fp1 = floatx80_add(fp1, fp2, status); /* Q */
2509              fp0 = floatx80_add(fp0, fp1, status); /* S*B1+Q */
2510  
2511              status->float_rounding_mode = user_rnd_mode;
2512              status->floatx80_rounding_precision = user_rnd_prec;
2513  
2514              a = floatx80_add(fp0, a, status);
2515  
2516              float_raise(float_flag_inexact, status);
2517  
2518              return a;
2519          } else { /* |X| < 2^(-65) */
2520              sc = packFloatx80(1, 1, one_sig);
2521              fp0 = a;
2522  
2523              if (aExp < 0x0033) { /* |X| < 2^(-16382) */
2524                  fp0 = floatx80_mul(fp0, float64_to_floatx80(
2525                                     make_float64(0x48B0000000000000), status),
2526                                     status);
2527                  fp0 = floatx80_add(fp0, sc, status);
2528  
2529                  status->float_rounding_mode = user_rnd_mode;
2530                  status->floatx80_rounding_precision = user_rnd_prec;
2531  
2532                  a = floatx80_mul(fp0, float64_to_floatx80(
2533                                   make_float64(0x3730000000000000), status),
2534                                   status);
2535              } else {
2536                  status->float_rounding_mode = user_rnd_mode;
2537                  status->floatx80_rounding_precision = user_rnd_prec;
2538  
2539                  a = floatx80_add(fp0, sc, status);
2540              }
2541  
2542              float_raise(float_flag_inexact, status);
2543  
2544              return a;
2545          }
2546      }
2547  }
2548  
2549  /*
2550   * Hyperbolic tangent
2551   */
2552  
2553  floatx80 floatx80_tanh(floatx80 a, float_status *status)
2554  {
2555      bool aSign, vSign;
2556      int32_t aExp, vExp;
2557      uint64_t aSig, vSig;
2558  
2559      FloatRoundMode user_rnd_mode;
2560      FloatX80RoundPrec user_rnd_prec;
2561  
2562      int32_t compact;
2563      floatx80 fp0, fp1;
2564      uint32_t sign;
2565  
2566      aSig = extractFloatx80Frac(a);
2567      aExp = extractFloatx80Exp(a);
2568      aSign = extractFloatx80Sign(a);
2569  
2570      if (aExp == 0x7FFF) {
2571          if ((uint64_t) (aSig << 1)) {
2572              return propagateFloatx80NaNOneArg(a, status);
2573          }
2574          return packFloatx80(aSign, one_exp, one_sig);
2575      }
2576  
2577      if (aExp == 0 && aSig == 0) {
2578          return packFloatx80(aSign, 0, 0);
2579      }
2580  
2581      user_rnd_mode = status->float_rounding_mode;
2582      user_rnd_prec = status->floatx80_rounding_precision;
2583      status->float_rounding_mode = float_round_nearest_even;
2584      status->floatx80_rounding_precision = floatx80_precision_x;
2585  
2586      compact = floatx80_make_compact(aExp, aSig);
2587  
2588      if (compact < 0x3FD78000 || compact > 0x3FFFDDCE) {
2589          /* TANHBORS */
2590          if (compact < 0x3FFF8000) {
2591              /* TANHSM */
2592              status->float_rounding_mode = user_rnd_mode;
2593              status->floatx80_rounding_precision = user_rnd_prec;
2594  
2595              a = floatx80_move(a, status);
2596  
2597              float_raise(float_flag_inexact, status);
2598  
2599              return a;
2600          } else {
2601              if (compact > 0x40048AA1) {
2602                  /* TANHHUGE */
2603                  sign = 0x3F800000;
2604                  sign |= aSign ? 0x80000000 : 0x00000000;
2605                  fp0 = float32_to_floatx80(make_float32(sign), status);
2606                  sign &= 0x80000000;
2607                  sign ^= 0x80800000; /* -SIGN(X)*EPS */
2608  
2609                  status->float_rounding_mode = user_rnd_mode;
2610                  status->floatx80_rounding_precision = user_rnd_prec;
2611  
2612                  a = floatx80_add(fp0, float32_to_floatx80(make_float32(sign),
2613                                   status), status);
2614  
2615                  float_raise(float_flag_inexact, status);
2616  
2617                  return a;
2618              } else {
2619                  fp0 = packFloatx80(0, aExp + 1, aSig); /* Y = 2|X| */
2620                  fp0 = floatx80_etox(fp0, status); /* FP0 IS EXP(Y) */
2621                  fp0 = floatx80_add(fp0, float32_to_floatx80(
2622                                     make_float32(0x3F800000),
2623                                     status), status); /* EXP(Y)+1 */
2624                  sign = aSign ? 0x80000000 : 0x00000000;
2625                  fp1 = floatx80_div(float32_to_floatx80(make_float32(
2626                                     sign ^ 0xC0000000), status), fp0,
2627                                     status); /* -SIGN(X)*2 / [EXP(Y)+1] */
2628                  fp0 = float32_to_floatx80(make_float32(sign | 0x3F800000),
2629                                            status); /* SIGN */
2630  
2631                  status->float_rounding_mode = user_rnd_mode;
2632                  status->floatx80_rounding_precision = user_rnd_prec;
2633  
2634                  a = floatx80_add(fp1, fp0, status);
2635  
2636                  float_raise(float_flag_inexact, status);
2637  
2638                  return a;
2639              }
2640          }
2641      } else { /* 2**(-40) < |X| < (5/2)LOG2 */
2642          fp0 = packFloatx80(0, aExp + 1, aSig); /* Y = 2|X| */
2643          fp0 = floatx80_etoxm1(fp0, status); /* FP0 IS Z = EXPM1(Y) */
2644          fp1 = floatx80_add(fp0, float32_to_floatx80(make_float32(0x40000000),
2645                             status),
2646                             status); /* Z+2 */
2647  
2648          vSign = extractFloatx80Sign(fp1);
2649          vExp = extractFloatx80Exp(fp1);
2650          vSig = extractFloatx80Frac(fp1);
2651  
2652          fp1 = packFloatx80(vSign ^ aSign, vExp, vSig);
2653  
2654          status->float_rounding_mode = user_rnd_mode;
2655          status->floatx80_rounding_precision = user_rnd_prec;
2656  
2657          a = floatx80_div(fp0, fp1, status);
2658  
2659          float_raise(float_flag_inexact, status);
2660  
2661          return a;
2662      }
2663  }
2664  
2665  /*
2666   * Hyperbolic sine
2667   */
2668  
2669  floatx80 floatx80_sinh(floatx80 a, float_status *status)
2670  {
2671      bool aSign;
2672      int32_t aExp;
2673      uint64_t aSig;
2674  
2675      FloatRoundMode user_rnd_mode;
2676      FloatX80RoundPrec user_rnd_prec;
2677  
2678      int32_t compact;
2679      floatx80 fp0, fp1, fp2;
2680      float32 fact;
2681  
2682      aSig = extractFloatx80Frac(a);
2683      aExp = extractFloatx80Exp(a);
2684      aSign = extractFloatx80Sign(a);
2685  
2686      if (aExp == 0x7FFF) {
2687          if ((uint64_t) (aSig << 1)) {
2688              return propagateFloatx80NaNOneArg(a, status);
2689          }
2690          return packFloatx80(aSign, floatx80_infinity.high,
2691                              floatx80_infinity.low);
2692      }
2693  
2694      if (aExp == 0 && aSig == 0) {
2695          return packFloatx80(aSign, 0, 0);
2696      }
2697  
2698      user_rnd_mode = status->float_rounding_mode;
2699      user_rnd_prec = status->floatx80_rounding_precision;
2700      status->float_rounding_mode = float_round_nearest_even;
2701      status->floatx80_rounding_precision = floatx80_precision_x;
2702  
2703      compact = floatx80_make_compact(aExp, aSig);
2704  
2705      if (compact > 0x400CB167) {
2706          /* SINHBIG */
2707          if (compact > 0x400CB2B3) {
2708              status->float_rounding_mode = user_rnd_mode;
2709              status->floatx80_rounding_precision = user_rnd_prec;
2710  
2711              return roundAndPackFloatx80(status->floatx80_rounding_precision,
2712                                          aSign, 0x8000, aSig, 0, status);
2713          } else {
2714              fp0 = floatx80_abs(a); /* Y = |X| */
2715              fp0 = floatx80_sub(fp0, float64_to_floatx80(
2716                                 make_float64(0x40C62D38D3D64634), status),
2717                                 status); /* (|X|-16381LOG2_LEAD) */
2718              fp0 = floatx80_sub(fp0, float64_to_floatx80(
2719                                 make_float64(0x3D6F90AEB1E75CC7), status),
2720                                 status); /* |X| - 16381 LOG2, ACCURATE */
2721              fp0 = floatx80_etox(fp0, status);
2722              fp2 = packFloatx80(aSign, 0x7FFB, one_sig);
2723  
2724              status->float_rounding_mode = user_rnd_mode;
2725              status->floatx80_rounding_precision = user_rnd_prec;
2726  
2727              a = floatx80_mul(fp0, fp2, status);
2728  
2729              float_raise(float_flag_inexact, status);
2730  
2731              return a;
2732          }
2733      } else { /* |X| < 16380 LOG2 */
2734          fp0 = floatx80_abs(a); /* Y = |X| */
2735          fp0 = floatx80_etoxm1(fp0, status); /* FP0 IS Z = EXPM1(Y) */
2736          fp1 = floatx80_add(fp0, float32_to_floatx80(make_float32(0x3F800000),
2737                             status), status); /* 1+Z */
2738          fp2 = fp0;
2739          fp0 = floatx80_div(fp0, fp1, status); /* Z/(1+Z) */
2740          fp0 = floatx80_add(fp0, fp2, status);
2741  
2742          fact = packFloat32(aSign, 0x7E, 0);
2743  
2744          status->float_rounding_mode = user_rnd_mode;
2745          status->floatx80_rounding_precision = user_rnd_prec;
2746  
2747          a = floatx80_mul(fp0, float32_to_floatx80(fact, status), status);
2748  
2749          float_raise(float_flag_inexact, status);
2750  
2751          return a;
2752      }
2753  }
2754  
2755  /*
2756   * Hyperbolic cosine
2757   */
2758  
2759  floatx80 floatx80_cosh(floatx80 a, float_status *status)
2760  {
2761      int32_t aExp;
2762      uint64_t aSig;
2763  
2764      FloatRoundMode user_rnd_mode;
2765      FloatX80RoundPrec user_rnd_prec;
2766  
2767      int32_t compact;
2768      floatx80 fp0, fp1;
2769  
2770      aSig = extractFloatx80Frac(a);
2771      aExp = extractFloatx80Exp(a);
2772  
2773      if (aExp == 0x7FFF) {
2774          if ((uint64_t) (aSig << 1)) {
2775              return propagateFloatx80NaNOneArg(a, status);
2776          }
2777          return packFloatx80(0, floatx80_infinity.high,
2778                              floatx80_infinity.low);
2779      }
2780  
2781      if (aExp == 0 && aSig == 0) {
2782          return packFloatx80(0, one_exp, one_sig);
2783      }
2784  
2785      user_rnd_mode = status->float_rounding_mode;
2786      user_rnd_prec = status->floatx80_rounding_precision;
2787      status->float_rounding_mode = float_round_nearest_even;
2788      status->floatx80_rounding_precision = floatx80_precision_x;
2789  
2790      compact = floatx80_make_compact(aExp, aSig);
2791  
2792      if (compact > 0x400CB167) {
2793          if (compact > 0x400CB2B3) {
2794              status->float_rounding_mode = user_rnd_mode;
2795              status->floatx80_rounding_precision = user_rnd_prec;
2796              return roundAndPackFloatx80(status->floatx80_rounding_precision, 0,
2797                                          0x8000, one_sig, 0, status);
2798          } else {
2799              fp0 = packFloatx80(0, aExp, aSig);
2800              fp0 = floatx80_sub(fp0, float64_to_floatx80(
2801                                 make_float64(0x40C62D38D3D64634), status),
2802                                 status);
2803              fp0 = floatx80_sub(fp0, float64_to_floatx80(
2804                                 make_float64(0x3D6F90AEB1E75CC7), status),
2805                                 status);
2806              fp0 = floatx80_etox(fp0, status);
2807              fp1 = packFloatx80(0, 0x7FFB, one_sig);
2808  
2809              status->float_rounding_mode = user_rnd_mode;
2810              status->floatx80_rounding_precision = user_rnd_prec;
2811  
2812              a = floatx80_mul(fp0, fp1, status);
2813  
2814              float_raise(float_flag_inexact, status);
2815  
2816              return a;
2817          }
2818      }
2819  
2820      fp0 = packFloatx80(0, aExp, aSig); /* |X| */
2821      fp0 = floatx80_etox(fp0, status); /* EXP(|X|) */
2822      fp0 = floatx80_mul(fp0, float32_to_floatx80(make_float32(0x3F000000),
2823                         status), status); /* (1/2)*EXP(|X|) */
2824      fp1 = float32_to_floatx80(make_float32(0x3E800000), status); /* 1/4 */
2825      fp1 = floatx80_div(fp1, fp0, status); /* 1/(2*EXP(|X|)) */
2826  
2827      status->float_rounding_mode = user_rnd_mode;
2828      status->floatx80_rounding_precision = user_rnd_prec;
2829  
2830      a = floatx80_add(fp0, fp1, status);
2831  
2832      float_raise(float_flag_inexact, status);
2833  
2834      return a;
2835  }
2836