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