2 * Ported from a work by Andreas Grabher for Previous, NeXT Computer Emulator,
3 * derived from NetBSD M68040 FPSP functions,
4 * derived from release 2a of the SoftFloat IEC/IEEE Floating-point Arithmetic
5 * Package. Those parts of the code (and some later contributions) are
6 * provided under that license, as detailed below.
7 * It has subsequently been modified by contributors to the QEMU Project,
8 * so some portions are provided under:
9 * the SoftFloat-2a license
13 * Any future contributions to this file will be taken to be licensed under
14 * the Softfloat-2a license unless specifically indicated otherwise.
17 /* Portions of this work are licensed under the terms of the GNU GPL,
18 * version 2 or later. See the COPYING file in the top-level directory.
21 #include "qemu/osdep.h"
22 #include "softfloat.h"
23 #include "fpu/softfloat-macros.h"
24 #include "softfloat_fpsp_tables.h"
27 #define piby2_exp 0x3FFF
28 #define pi_sig LIT64(0xc90fdaa22168c235)
30 static floatx80
propagateFloatx80NaNOneArg(floatx80 a
, float_status
*status
)
32 if (floatx80_is_signaling_nan(a
, status
)) {
33 float_raise(float_flag_invalid
, status
);
34 a
= floatx80_silence_nan(a
, status
);
37 if (status
->default_nan_mode
) {
38 return floatx80_default_nan(status
);
44 /*----------------------------------------------------------------------------
45 | Returns the modulo remainder of the extended double-precision floating-point
46 | value `a' with respect to the corresponding value `b'.
47 *----------------------------------------------------------------------------*/
49 floatx80
floatx80_mod(floatx80 a
, floatx80 b
, float_status
*status
)
52 int32_t aExp
, bExp
, expDiff
;
53 uint64_t aSig0
, aSig1
, bSig
;
54 uint64_t qTemp
, term0
, term1
;
56 aSig0
= extractFloatx80Frac(a
);
57 aExp
= extractFloatx80Exp(a
);
58 aSign
= extractFloatx80Sign(a
);
59 bSig
= extractFloatx80Frac(b
);
60 bExp
= extractFloatx80Exp(b
);
63 if ((uint64_t) (aSig0
<< 1)
64 || ((bExp
== 0x7FFF) && (uint64_t) (bSig
<< 1))) {
65 return propagateFloatx80NaN(a
, b
, status
);
70 if ((uint64_t) (bSig
<< 1)) {
71 return propagateFloatx80NaN(a
, b
, status
);
78 float_raise(float_flag_invalid
, status
);
79 return floatx80_default_nan(status
);
81 normalizeFloatx80Subnormal(bSig
, &bExp
, &bSig
);
84 if ((uint64_t) (aSig0
<< 1) == 0) {
87 normalizeFloatx80Subnormal(aSig0
, &aExp
, &aSig0
);
89 bSig
|= LIT64(0x8000000000000000);
91 expDiff
= aExp
- bExp
;
96 qTemp
= (bSig
<= aSig0
);
101 while (0 < expDiff
) {
102 qTemp
= estimateDiv128To64(aSig0
, aSig1
, bSig
);
103 qTemp
= (2 < qTemp
) ? qTemp
- 2 : 0;
104 mul64To128(bSig
, qTemp
, &term0
, &term1
);
105 sub128(aSig0
, aSig1
, term0
, term1
, &aSig0
, &aSig1
);
106 shortShift128Left(aSig0
, aSig1
, 62, &aSig0
, &aSig1
);
111 qTemp
= estimateDiv128To64(aSig0
, aSig1
, bSig
);
112 qTemp
= (2 < qTemp
) ? qTemp
- 2 : 0;
113 qTemp
>>= 64 - expDiff
;
114 mul64To128(bSig
, qTemp
<< (64 - expDiff
), &term0
, &term1
);
115 sub128(aSig0
, aSig1
, term0
, term1
, &aSig0
, &aSig1
);
116 shortShift128Left(0, bSig
, 64 - expDiff
, &term0
, &term1
);
117 while (le128(term0
, term1
, aSig0
, aSig1
)) {
119 sub128(aSig0
, aSig1
, term0
, term1
, &aSig0
, &aSig1
);
123 normalizeRoundAndPackFloatx80(
124 80, zSign
, bExp
+ expDiff
, aSig0
, aSig1
, status
);
127 /*----------------------------------------------------------------------------
128 | Returns the mantissa of the extended double-precision floating-point
130 *----------------------------------------------------------------------------*/
132 floatx80
floatx80_getman(floatx80 a
, float_status
*status
)
138 aSig
= extractFloatx80Frac(a
);
139 aExp
= extractFloatx80Exp(a
);
140 aSign
= extractFloatx80Sign(a
);
142 if (aExp
== 0x7FFF) {
143 if ((uint64_t) (aSig
<< 1)) {
144 return propagateFloatx80NaNOneArg(a
, status
);
146 float_raise(float_flag_invalid
, status
);
147 return floatx80_default_nan(status
);
152 return packFloatx80(aSign
, 0, 0);
154 normalizeFloatx80Subnormal(aSig
, &aExp
, &aSig
);
157 return roundAndPackFloatx80(status
->floatx80_rounding_precision
, aSign
,
158 0x3FFF, aSig
, 0, status
);
161 /*----------------------------------------------------------------------------
162 | Returns the exponent of the extended double-precision floating-point
163 | value `a' as an extended double-precision value.
164 *----------------------------------------------------------------------------*/
166 floatx80
floatx80_getexp(floatx80 a
, float_status
*status
)
172 aSig
= extractFloatx80Frac(a
);
173 aExp
= extractFloatx80Exp(a
);
174 aSign
= extractFloatx80Sign(a
);
176 if (aExp
== 0x7FFF) {
177 if ((uint64_t) (aSig
<< 1)) {
178 return propagateFloatx80NaNOneArg(a
, status
);
180 float_raise(float_flag_invalid
, status
);
181 return floatx80_default_nan(status
);
186 return packFloatx80(aSign
, 0, 0);
188 normalizeFloatx80Subnormal(aSig
, &aExp
, &aSig
);
191 return int32_to_floatx80(aExp
- 0x3FFF, status
);
194 /*----------------------------------------------------------------------------
195 | Scales extended double-precision floating-point value in operand `a' by
196 | value `b'. The function truncates the value in the second operand 'b' to
197 | an integral value and adds that value to the exponent of the operand 'a'.
198 | The operation performed according to the IEC/IEEE Standard for Binary
199 | Floating-Point Arithmetic.
200 *----------------------------------------------------------------------------*/
202 floatx80
floatx80_scale(floatx80 a
, floatx80 b
, float_status
*status
)
205 int32_t aExp
, bExp
, shiftCount
;
208 aSig
= extractFloatx80Frac(a
);
209 aExp
= extractFloatx80Exp(a
);
210 aSign
= extractFloatx80Sign(a
);
211 bSig
= extractFloatx80Frac(b
);
212 bExp
= extractFloatx80Exp(b
);
213 bSign
= extractFloatx80Sign(b
);
215 if (bExp
== 0x7FFF) {
216 if ((uint64_t) (bSig
<< 1) ||
217 ((aExp
== 0x7FFF) && (uint64_t) (aSig
<< 1))) {
218 return propagateFloatx80NaN(a
, b
, status
);
220 float_raise(float_flag_invalid
, status
);
221 return floatx80_default_nan(status
);
223 if (aExp
== 0x7FFF) {
224 if ((uint64_t) (aSig
<< 1)) {
225 return propagateFloatx80NaN(a
, b
, status
);
227 return packFloatx80(aSign
, floatx80_infinity
.high
,
228 floatx80_infinity
.low
);
232 return packFloatx80(aSign
, 0, 0);
237 normalizeFloatx80Subnormal(aSig
, &aExp
, &aSig
);
245 aExp
= bSign
? -0x6001 : 0xE000;
246 return roundAndPackFloatx80(status
->floatx80_rounding_precision
,
247 aSign
, aExp
, aSig
, 0, status
);
250 shiftCount
= 0x403E - bExp
;
252 aExp
= bSign
? (aExp
- bSig
) : (aExp
+ bSig
);
254 return roundAndPackFloatx80(status
->floatx80_rounding_precision
,
255 aSign
, aExp
, aSig
, 0, status
);
258 floatx80
floatx80_move(floatx80 a
, float_status
*status
)
264 aSig
= extractFloatx80Frac(a
);
265 aExp
= extractFloatx80Exp(a
);
266 aSign
= extractFloatx80Sign(a
);
268 if (aExp
== 0x7FFF) {
269 if ((uint64_t)(aSig
<< 1)) {
270 return propagateFloatx80NaNOneArg(a
, status
);
278 normalizeRoundAndPackFloatx80(status
->floatx80_rounding_precision
,
279 aSign
, aExp
, aSig
, 0, status
);
281 return roundAndPackFloatx80(status
->floatx80_rounding_precision
, aSign
,
282 aExp
, aSig
, 0, status
);
285 /*----------------------------------------------------------------------------
286 | Algorithms for transcendental functions supported by MC68881 and MC68882
287 | mathematical coprocessors. The functions are derived from FPSP library.
288 *----------------------------------------------------------------------------*/
290 #define one_exp 0x3FFF
291 #define one_sig LIT64(0x8000000000000000)
293 /*----------------------------------------------------------------------------
294 | Function for compactifying extended double-precision floating point values.
295 *----------------------------------------------------------------------------*/
297 static int32_t floatx80_make_compact(int32_t aExp
, uint64_t aSig
)
299 return (aExp
<< 16) | (aSig
>> 48);
302 /*----------------------------------------------------------------------------
303 | Log base e of x plus 1
304 *----------------------------------------------------------------------------*/
306 floatx80
floatx80_lognp1(floatx80 a
, float_status
*status
)
312 int8_t user_rnd_mode
, user_rnd_prec
;
314 int32_t compact
, j
, k
;
315 floatx80 fp0
, fp1
, fp2
, fp3
, f
, logof2
, klog2
, saveu
;
317 aSig
= extractFloatx80Frac(a
);
318 aExp
= extractFloatx80Exp(a
);
319 aSign
= extractFloatx80Sign(a
);
321 if (aExp
== 0x7FFF) {
322 if ((uint64_t) (aSig
<< 1)) {
323 propagateFloatx80NaNOneArg(a
, status
);
326 float_raise(float_flag_invalid
, status
);
327 return floatx80_default_nan(status
);
329 return packFloatx80(0, floatx80_infinity
.high
, floatx80_infinity
.low
);
332 if (aExp
== 0 && aSig
== 0) {
333 return packFloatx80(aSign
, 0, 0);
336 if (aSign
&& aExp
>= one_exp
) {
337 if (aExp
== one_exp
&& aSig
== one_sig
) {
338 float_raise(float_flag_divbyzero
, status
);
339 return packFloatx80(aSign
, floatx80_infinity
.high
,
340 floatx80_infinity
.low
);
342 float_raise(float_flag_invalid
, status
);
343 return floatx80_default_nan(status
);
346 if (aExp
< 0x3f99 || (aExp
== 0x3f99 && aSig
== one_sig
)) {
347 /* <= min threshold */
348 float_raise(float_flag_inexact
, status
);
349 return floatx80_move(a
, status
);
352 user_rnd_mode
= status
->float_rounding_mode
;
353 user_rnd_prec
= status
->floatx80_rounding_precision
;
354 status
->float_rounding_mode
= float_round_nearest_even
;
355 status
->floatx80_rounding_precision
= 80;
357 compact
= floatx80_make_compact(aExp
, aSig
);
362 fp0
= floatx80_add(fp0
, float32_to_floatx80(make_float32(0x3F800000),
363 status
), status
); /* X = (1+Z) */
365 aExp
= extractFloatx80Exp(fp0
);
366 aSig
= extractFloatx80Frac(fp0
);
368 compact
= floatx80_make_compact(aExp
, aSig
);
370 if (compact
< 0x3FFE8000 || compact
> 0x3FFFC000) {
371 /* |X| < 1/2 or |X| > 3/2 */
373 fp1
= int32_to_floatx80(k
, status
);
375 fSig
= (aSig
& LIT64(0xFE00000000000000)) | LIT64(0x0100000000000000);
376 j
= (fSig
>> 56) & 0x7E; /* DISPLACEMENT FOR 1/F */
378 f
= packFloatx80(0, 0x3FFF, fSig
); /* F */
379 fp0
= packFloatx80(0, 0x3FFF, aSig
); /* Y */
381 fp0
= floatx80_sub(fp0
, f
, status
); /* Y-F */
385 fp0
= floatx80_mul(fp0
, log_tbl
[j
], status
); /* FP0 IS U = (Y-F)/F */
386 logof2
= packFloatx80(0, 0x3FFE, LIT64(0xB17217F7D1CF79AC));
387 klog2
= floatx80_mul(fp1
, logof2
, status
); /* FP1 IS K*LOG2 */
388 fp2
= floatx80_mul(fp0
, fp0
, status
); /* FP2 IS V=U*U */
393 fp1
= floatx80_mul(fp1
, float64_to_floatx80(
394 make_float64(0x3FC2499AB5E4040B), status
),
396 fp2
= floatx80_mul(fp2
, float64_to_floatx80(
397 make_float64(0xBFC555B5848CB7DB), status
),
399 fp1
= floatx80_add(fp1
, float64_to_floatx80(
400 make_float64(0x3FC99999987D8730), status
),
401 status
); /* A4+V*A6 */
402 fp2
= floatx80_add(fp2
, float64_to_floatx80(
403 make_float64(0xBFCFFFFFFF6F7E97), status
),
404 status
); /* A3+V*A5 */
405 fp1
= floatx80_mul(fp1
, fp3
, status
); /* V*(A4+V*A6) */
406 fp2
= floatx80_mul(fp2
, fp3
, status
); /* V*(A3+V*A5) */
407 fp1
= floatx80_add(fp1
, float64_to_floatx80(
408 make_float64(0x3FD55555555555A4), status
),
409 status
); /* A2+V*(A4+V*A6) */
410 fp2
= floatx80_add(fp2
, float64_to_floatx80(
411 make_float64(0xBFE0000000000008), status
),
412 status
); /* A1+V*(A3+V*A5) */
413 fp1
= floatx80_mul(fp1
, fp3
, status
); /* V*(A2+V*(A4+V*A6)) */
414 fp2
= floatx80_mul(fp2
, fp3
, status
); /* V*(A1+V*(A3+V*A5)) */
415 fp1
= floatx80_mul(fp1
, fp0
, status
); /* U*V*(A2+V*(A4+V*A6)) */
416 fp0
= floatx80_add(fp0
, fp2
, status
); /* U+V*(A1+V*(A3+V*A5)) */
418 fp1
= floatx80_add(fp1
, log_tbl
[j
+ 1],
419 status
); /* LOG(F)+U*V*(A2+V*(A4+V*A6)) */
420 fp0
= floatx80_add(fp0
, fp1
, status
); /* FP0 IS LOG(F) + LOG(1+U) */
422 status
->float_rounding_mode
= user_rnd_mode
;
423 status
->floatx80_rounding_precision
= user_rnd_prec
;
425 a
= floatx80_add(fp0
, klog2
, status
);
427 float_raise(float_flag_inexact
, status
);
430 } else if (compact
< 0x3FFEF07D || compact
> 0x3FFF8841) {
431 /* |X| < 1/16 or |X| > -1/16 */
433 fSig
= (aSig
& LIT64(0xFE00000000000000)) | LIT64(0x0100000000000000);
434 f
= packFloatx80(0, 0x3FFF, fSig
); /* F */
435 j
= (fSig
>> 56) & 0x7E; /* DISPLACEMENT FOR 1/F */
437 if (compact
>= 0x3FFF8000) { /* 1+Z >= 1 */
439 fp0
= floatx80_sub(float32_to_floatx80(make_float32(0x3F800000),
440 status
), f
, status
); /* 1-F */
441 fp0
= floatx80_add(fp0
, fp1
, status
); /* FP0 IS Y-F = (1-F)+Z */
442 fp1
= packFloatx80(0, 0, 0); /* K = 0 */
445 fp0
= floatx80_sub(float32_to_floatx80(make_float32(0x40000000),
446 status
), f
, status
); /* 2-F */
447 fp1
= floatx80_add(fp1
, fp1
, status
); /* 2Z */
448 fp0
= floatx80_add(fp0
, fp1
, status
); /* FP0 IS Y-F = (2-F)+2Z */
449 fp1
= packFloatx80(1, one_exp
, one_sig
); /* K = -1 */
454 fp1
= floatx80_add(fp1
, fp1
, status
); /* FP1 IS 2Z */
455 fp0
= floatx80_add(fp0
, float32_to_floatx80(make_float32(0x3F800000),
456 status
), status
); /* FP0 IS 1+X */
459 fp1
= floatx80_div(fp1
, fp0
, status
); /* U */
461 fp0
= floatx80_mul(fp1
, fp1
, status
); /* FP0 IS V = U*U */
462 fp1
= floatx80_mul(fp0
, fp0
, status
); /* FP1 IS W = V*V */
464 fp3
= float64_to_floatx80(make_float64(0x3F175496ADD7DAD6),
466 fp2
= float64_to_floatx80(make_float64(0x3F3C71C2FE80C7E0),
468 fp3
= floatx80_mul(fp3
, fp1
, status
); /* W*B5 */
469 fp2
= floatx80_mul(fp2
, fp1
, status
); /* W*B4 */
470 fp3
= floatx80_add(fp3
, float64_to_floatx80(
471 make_float64(0x3F624924928BCCFF), status
),
472 status
); /* B3+W*B5 */
473 fp2
= floatx80_add(fp2
, float64_to_floatx80(
474 make_float64(0x3F899999999995EC), status
),
475 status
); /* B2+W*B4 */
476 fp1
= floatx80_mul(fp1
, fp3
, status
); /* W*(B3+W*B5) */
477 fp2
= floatx80_mul(fp2
, fp0
, status
); /* V*(B2+W*B4) */
478 fp1
= floatx80_add(fp1
, float64_to_floatx80(
479 make_float64(0x3FB5555555555555), status
),
480 status
); /* B1+W*(B3+W*B5) */
482 fp0
= floatx80_mul(fp0
, saveu
, status
); /* FP0 IS U*V */
483 fp1
= floatx80_add(fp1
, fp2
,
484 status
); /* B1+W*(B3+W*B5) + V*(B2+W*B4) */
485 fp0
= floatx80_mul(fp0
, fp1
,
486 status
); /* U*V*([B1+W*(B3+W*B5)] + [V*(B2+W*B4)]) */
488 status
->float_rounding_mode
= user_rnd_mode
;
489 status
->floatx80_rounding_precision
= user_rnd_prec
;
491 a
= floatx80_add(fp0
, saveu
, status
);
493 /*if (!floatx80_is_zero(a)) { */
494 float_raise(float_flag_inexact
, status
);
501 /*----------------------------------------------------------------------------
503 *----------------------------------------------------------------------------*/
505 floatx80
floatx80_logn(floatx80 a
, float_status
*status
)
511 int8_t user_rnd_mode
, user_rnd_prec
;
513 int32_t compact
, j
, k
, adjk
;
514 floatx80 fp0
, fp1
, fp2
, fp3
, f
, logof2
, klog2
, saveu
;
516 aSig
= extractFloatx80Frac(a
);
517 aExp
= extractFloatx80Exp(a
);
518 aSign
= extractFloatx80Sign(a
);
520 if (aExp
== 0x7FFF) {
521 if ((uint64_t) (aSig
<< 1)) {
522 propagateFloatx80NaNOneArg(a
, status
);
525 return packFloatx80(0, floatx80_infinity
.high
,
526 floatx80_infinity
.low
);
533 if (aSig
== 0) { /* zero */
534 float_raise(float_flag_divbyzero
, status
);
535 return packFloatx80(1, floatx80_infinity
.high
,
536 floatx80_infinity
.low
);
538 if ((aSig
& one_sig
) == 0) { /* denormal */
539 normalizeFloatx80Subnormal(aSig
, &aExp
, &aSig
);
542 a
= packFloatx80(aSign
, aExp
, aSig
);
547 float_raise(float_flag_invalid
, status
);
548 return floatx80_default_nan(status
);
551 user_rnd_mode
= status
->float_rounding_mode
;
552 user_rnd_prec
= status
->floatx80_rounding_precision
;
553 status
->float_rounding_mode
= float_round_nearest_even
;
554 status
->floatx80_rounding_precision
= 80;
556 compact
= floatx80_make_compact(aExp
, aSig
);
558 if (compact
< 0x3FFEF07D || compact
> 0x3FFF8841) {
559 /* |X| < 15/16 or |X| > 17/16 */
562 fp1
= int32_to_floatx80(k
, status
);
564 fSig
= (aSig
& LIT64(0xFE00000000000000)) | LIT64(0x0100000000000000);
565 j
= (fSig
>> 56) & 0x7E; /* DISPLACEMENT FOR 1/F */
567 f
= packFloatx80(0, 0x3FFF, fSig
); /* F */
568 fp0
= packFloatx80(0, 0x3FFF, aSig
); /* Y */
570 fp0
= floatx80_sub(fp0
, f
, status
); /* Y-F */
573 fp0
= floatx80_mul(fp0
, log_tbl
[j
], status
); /* FP0 IS U = (Y-F)/F */
574 logof2
= packFloatx80(0, 0x3FFE, LIT64(0xB17217F7D1CF79AC));
575 klog2
= floatx80_mul(fp1
, logof2
, status
); /* FP1 IS K*LOG2 */
576 fp2
= floatx80_mul(fp0
, fp0
, status
); /* FP2 IS V=U*U */
581 fp1
= floatx80_mul(fp1
, float64_to_floatx80(
582 make_float64(0x3FC2499AB5E4040B), status
),
584 fp2
= floatx80_mul(fp2
, float64_to_floatx80(
585 make_float64(0xBFC555B5848CB7DB), status
),
587 fp1
= floatx80_add(fp1
, float64_to_floatx80(
588 make_float64(0x3FC99999987D8730), status
),
589 status
); /* A4+V*A6 */
590 fp2
= floatx80_add(fp2
, float64_to_floatx80(
591 make_float64(0xBFCFFFFFFF6F7E97), status
),
592 status
); /* A3+V*A5 */
593 fp1
= floatx80_mul(fp1
, fp3
, status
); /* V*(A4+V*A6) */
594 fp2
= floatx80_mul(fp2
, fp3
, status
); /* V*(A3+V*A5) */
595 fp1
= floatx80_add(fp1
, float64_to_floatx80(
596 make_float64(0x3FD55555555555A4), status
),
597 status
); /* A2+V*(A4+V*A6) */
598 fp2
= floatx80_add(fp2
, float64_to_floatx80(
599 make_float64(0xBFE0000000000008), status
),
600 status
); /* A1+V*(A3+V*A5) */
601 fp1
= floatx80_mul(fp1
, fp3
, status
); /* V*(A2+V*(A4+V*A6)) */
602 fp2
= floatx80_mul(fp2
, fp3
, status
); /* V*(A1+V*(A3+V*A5)) */
603 fp1
= floatx80_mul(fp1
, fp0
, status
); /* U*V*(A2+V*(A4+V*A6)) */
604 fp0
= floatx80_add(fp0
, fp2
, status
); /* U+V*(A1+V*(A3+V*A5)) */
606 fp1
= floatx80_add(fp1
, log_tbl
[j
+ 1],
607 status
); /* LOG(F)+U*V*(A2+V*(A4+V*A6)) */
608 fp0
= floatx80_add(fp0
, fp1
, status
); /* FP0 IS LOG(F) + LOG(1+U) */
610 status
->float_rounding_mode
= user_rnd_mode
;
611 status
->floatx80_rounding_precision
= user_rnd_prec
;
613 a
= floatx80_add(fp0
, klog2
, status
);
615 float_raise(float_flag_inexact
, status
);
618 } else { /* |X-1| >= 1/16 */
621 fp1
= floatx80_sub(fp1
, float32_to_floatx80(make_float32(0x3F800000),
622 status
), status
); /* FP1 IS X-1 */
623 fp0
= floatx80_add(fp0
, float32_to_floatx80(make_float32(0x3F800000),
624 status
), status
); /* FP0 IS X+1 */
625 fp1
= floatx80_add(fp1
, fp1
, status
); /* FP1 IS 2(X-1) */
628 fp1
= floatx80_div(fp1
, fp0
, status
); /* U */
630 fp0
= floatx80_mul(fp1
, fp1
, status
); /* FP0 IS V = U*U */
631 fp1
= floatx80_mul(fp0
, fp0
, status
); /* FP1 IS W = V*V */
633 fp3
= float64_to_floatx80(make_float64(0x3F175496ADD7DAD6),
635 fp2
= float64_to_floatx80(make_float64(0x3F3C71C2FE80C7E0),
637 fp3
= floatx80_mul(fp3
, fp1
, status
); /* W*B5 */
638 fp2
= floatx80_mul(fp2
, fp1
, status
); /* W*B4 */
639 fp3
= floatx80_add(fp3
, float64_to_floatx80(
640 make_float64(0x3F624924928BCCFF), status
),
641 status
); /* B3+W*B5 */
642 fp2
= floatx80_add(fp2
, float64_to_floatx80(
643 make_float64(0x3F899999999995EC), status
),
644 status
); /* B2+W*B4 */
645 fp1
= floatx80_mul(fp1
, fp3
, status
); /* W*(B3+W*B5) */
646 fp2
= floatx80_mul(fp2
, fp0
, status
); /* V*(B2+W*B4) */
647 fp1
= floatx80_add(fp1
, float64_to_floatx80(
648 make_float64(0x3FB5555555555555), status
),
649 status
); /* B1+W*(B3+W*B5) */
651 fp0
= floatx80_mul(fp0
, saveu
, status
); /* FP0 IS U*V */
652 fp1
= floatx80_add(fp1
, fp2
, status
); /* B1+W*(B3+W*B5) + V*(B2+W*B4) */
653 fp0
= floatx80_mul(fp0
, fp1
,
654 status
); /* U*V*([B1+W*(B3+W*B5)] + [V*(B2+W*B4)]) */
656 status
->float_rounding_mode
= user_rnd_mode
;
657 status
->floatx80_rounding_precision
= user_rnd_prec
;
659 a
= floatx80_add(fp0
, saveu
, status
);
661 /*if (!floatx80_is_zero(a)) { */
662 float_raise(float_flag_inexact
, status
);
669 /*----------------------------------------------------------------------------
671 *----------------------------------------------------------------------------*/
673 floatx80
floatx80_log10(floatx80 a
, float_status
*status
)
679 int8_t user_rnd_mode
, user_rnd_prec
;
683 aSig
= extractFloatx80Frac(a
);
684 aExp
= extractFloatx80Exp(a
);
685 aSign
= extractFloatx80Sign(a
);
687 if (aExp
== 0x7FFF) {
688 if ((uint64_t) (aSig
<< 1)) {
689 propagateFloatx80NaNOneArg(a
, status
);
692 return packFloatx80(0, floatx80_infinity
.high
,
693 floatx80_infinity
.low
);
697 if (aExp
== 0 && aSig
== 0) {
698 float_raise(float_flag_divbyzero
, status
);
699 return packFloatx80(1, floatx80_infinity
.high
,
700 floatx80_infinity
.low
);
704 float_raise(float_flag_invalid
, status
);
705 return floatx80_default_nan(status
);
708 user_rnd_mode
= status
->float_rounding_mode
;
709 user_rnd_prec
= status
->floatx80_rounding_precision
;
710 status
->float_rounding_mode
= float_round_nearest_even
;
711 status
->floatx80_rounding_precision
= 80;
713 fp0
= floatx80_logn(a
, status
);
714 fp1
= packFloatx80(0, 0x3FFD, LIT64(0xDE5BD8A937287195)); /* INV_L10 */
716 status
->float_rounding_mode
= user_rnd_mode
;
717 status
->floatx80_rounding_precision
= user_rnd_prec
;
719 a
= floatx80_mul(fp0
, fp1
, status
); /* LOGN(X)*INV_L10 */
721 float_raise(float_flag_inexact
, status
);
726 /*----------------------------------------------------------------------------
728 *----------------------------------------------------------------------------*/
730 floatx80
floatx80_log2(floatx80 a
, float_status
*status
)
736 int8_t user_rnd_mode
, user_rnd_prec
;
740 aSig
= extractFloatx80Frac(a
);
741 aExp
= extractFloatx80Exp(a
);
742 aSign
= extractFloatx80Sign(a
);
744 if (aExp
== 0x7FFF) {
745 if ((uint64_t) (aSig
<< 1)) {
746 propagateFloatx80NaNOneArg(a
, status
);
749 return packFloatx80(0, floatx80_infinity
.high
,
750 floatx80_infinity
.low
);
756 float_raise(float_flag_divbyzero
, status
);
757 return packFloatx80(1, floatx80_infinity
.high
,
758 floatx80_infinity
.low
);
760 normalizeFloatx80Subnormal(aSig
, &aExp
, &aSig
);
764 float_raise(float_flag_invalid
, status
);
765 return floatx80_default_nan(status
);
768 user_rnd_mode
= status
->float_rounding_mode
;
769 user_rnd_prec
= status
->floatx80_rounding_precision
;
770 status
->float_rounding_mode
= float_round_nearest_even
;
771 status
->floatx80_rounding_precision
= 80;
773 if (aSig
== one_sig
) { /* X is 2^k */
774 status
->float_rounding_mode
= user_rnd_mode
;
775 status
->floatx80_rounding_precision
= user_rnd_prec
;
777 a
= int32_to_floatx80(aExp
- 0x3FFF, status
);
779 fp0
= floatx80_logn(a
, status
);
780 fp1
= packFloatx80(0, 0x3FFF, LIT64(0xB8AA3B295C17F0BC)); /* INV_L2 */
782 status
->float_rounding_mode
= user_rnd_mode
;
783 status
->floatx80_rounding_precision
= user_rnd_prec
;
785 a
= floatx80_mul(fp0
, fp1
, status
); /* LOGN(X)*INV_L2 */
788 float_raise(float_flag_inexact
, status
);
793 /*----------------------------------------------------------------------------
795 *----------------------------------------------------------------------------*/
797 floatx80
floatx80_etox(floatx80 a
, float_status
*status
)
803 int8_t user_rnd_mode
, user_rnd_prec
;
805 int32_t compact
, n
, j
, k
, m
, m1
;
806 floatx80 fp0
, fp1
, fp2
, fp3
, l2
, scale
, adjscale
;
809 aSig
= extractFloatx80Frac(a
);
810 aExp
= extractFloatx80Exp(a
);
811 aSign
= extractFloatx80Sign(a
);
813 if (aExp
== 0x7FFF) {
814 if ((uint64_t) (aSig
<< 1)) {
815 return propagateFloatx80NaNOneArg(a
, status
);
818 return packFloatx80(0, 0, 0);
820 return packFloatx80(0, floatx80_infinity
.high
,
821 floatx80_infinity
.low
);
824 if (aExp
== 0 && aSig
== 0) {
825 return packFloatx80(0, one_exp
, one_sig
);
828 user_rnd_mode
= status
->float_rounding_mode
;
829 user_rnd_prec
= status
->floatx80_rounding_precision
;
830 status
->float_rounding_mode
= float_round_nearest_even
;
831 status
->floatx80_rounding_precision
= 80;
835 if (aExp
>= 0x3FBE) { /* |X| >= 2^(-65) */
836 compact
= floatx80_make_compact(aExp
, aSig
);
838 if (compact
< 0x400CB167) { /* |X| < 16380 log2 */
841 fp0
= floatx80_mul(fp0
, float32_to_floatx80(
842 make_float32(0x42B8AA3B), status
),
843 status
); /* 64/log2 * X */
845 n
= floatx80_to_int32(fp0
, status
); /* int(64/log2*X) */
846 fp0
= int32_to_floatx80(n
, status
);
848 j
= n
& 0x3F; /* J = N mod 64 */
849 m
= n
/ 64; /* NOTE: this is really arithmetic right shift by 6 */
851 /* arithmetic right shift is division and
852 * round towards minus infinity
856 m
+= 0x3FFF; /* biased exponent of 2^(M) */
860 fp0
= floatx80_mul(fp0
, float32_to_floatx80(
861 make_float32(0xBC317218), status
),
862 status
); /* N * L1, L1 = lead(-log2/64) */
863 l2
= packFloatx80(0, 0x3FDC, LIT64(0x82E308654361C4C6));
864 fp2
= floatx80_mul(fp2
, l2
, status
); /* N * L2, L1+L2 = -log2/64 */
865 fp0
= floatx80_add(fp0
, fp1
, status
); /* X + N*L1 */
866 fp0
= floatx80_add(fp0
, fp2
, status
); /* R */
868 fp1
= floatx80_mul(fp0
, fp0
, status
); /* S = R*R */
869 fp2
= float32_to_floatx80(make_float32(0x3AB60B70),
871 fp2
= floatx80_mul(fp2
, fp1
, status
); /* fp2 is S*A5 */
872 fp3
= floatx80_mul(float32_to_floatx80(make_float32(0x3C088895),
874 status
); /* fp3 is S*A4 */
875 fp2
= floatx80_add(fp2
, float64_to_floatx80(make_float64(
876 0x3FA5555555554431), status
),
877 status
); /* fp2 is A3+S*A5 */
878 fp3
= floatx80_add(fp3
, float64_to_floatx80(make_float64(
879 0x3FC5555555554018), status
),
880 status
); /* fp3 is A2+S*A4 */
881 fp2
= floatx80_mul(fp2
, fp1
, status
); /* fp2 is S*(A3+S*A5) */
882 fp3
= floatx80_mul(fp3
, fp1
, status
); /* fp3 is S*(A2+S*A4) */
883 fp2
= floatx80_add(fp2
, float32_to_floatx80(
884 make_float32(0x3F000000), status
),
885 status
); /* fp2 is A1+S*(A3+S*A5) */
886 fp3
= floatx80_mul(fp3
, fp0
, status
); /* fp3 IS R*S*(A2+S*A4) */
887 fp2
= floatx80_mul(fp2
, fp1
,
888 status
); /* fp2 IS S*(A1+S*(A3+S*A5)) */
889 fp0
= floatx80_add(fp0
, fp3
, status
); /* fp0 IS R+R*S*(A2+S*A4) */
890 fp0
= floatx80_add(fp0
, fp2
, status
); /* fp0 IS EXP(R) - 1 */
893 fp0
= floatx80_mul(fp0
, fp1
, status
); /* 2^(J/64)*(Exp(R)-1) */
894 fp0
= floatx80_add(fp0
, float32_to_floatx80(exp_tbl2
[j
], status
),
895 status
); /* accurate 2^(J/64) */
896 fp0
= floatx80_add(fp0
, fp1
,
897 status
); /* 2^(J/64) + 2^(J/64)*(Exp(R)-1) */
899 scale
= packFloatx80(0, m
, one_sig
);
901 adjscale
= packFloatx80(0, m1
, one_sig
);
902 fp0
= floatx80_mul(fp0
, adjscale
, status
);
905 status
->float_rounding_mode
= user_rnd_mode
;
906 status
->floatx80_rounding_precision
= user_rnd_prec
;
908 a
= floatx80_mul(fp0
, scale
, status
);
910 float_raise(float_flag_inexact
, status
);
913 } else { /* |X| >= 16380 log2 */
914 if (compact
> 0x400CB27C) { /* |X| >= 16480 log2 */
915 status
->float_rounding_mode
= user_rnd_mode
;
916 status
->floatx80_rounding_precision
= user_rnd_prec
;
918 a
= roundAndPackFloatx80(
919 status
->floatx80_rounding_precision
,
920 0, -0x1000, aSig
, 0, status
);
922 a
= roundAndPackFloatx80(
923 status
->floatx80_rounding_precision
,
924 0, 0x8000, aSig
, 0, status
);
926 float_raise(float_flag_inexact
, status
);
932 fp0
= floatx80_mul(fp0
, float32_to_floatx80(
933 make_float32(0x42B8AA3B), status
),
934 status
); /* 64/log2 * X */
936 n
= floatx80_to_int32(fp0
, status
); /* int(64/log2*X) */
937 fp0
= int32_to_floatx80(n
, status
);
939 j
= n
& 0x3F; /* J = N mod 64 */
940 /* NOTE: this is really arithmetic right shift by 6 */
943 /* arithmetic right shift is division and
944 * round towards minus infinity
948 /* NOTE: this is really arithmetic right shift by 1 */
950 if (k
< 0 && (k
& 1)) {
951 /* arithmetic right shift is division and
952 * round towards minus infinity
957 m1
+= 0x3FFF; /* biased exponent of 2^(M1) */
958 m
+= 0x3FFF; /* biased exponent of 2^(M) */
963 } else { /* |X| < 2^(-65) */
964 status
->float_rounding_mode
= user_rnd_mode
;
965 status
->floatx80_rounding_precision
= user_rnd_prec
;
967 a
= floatx80_add(a
, float32_to_floatx80(make_float32(0x3F800000),
968 status
), status
); /* 1 + X */
970 float_raise(float_flag_inexact
, status
);
976 /*----------------------------------------------------------------------------
978 *----------------------------------------------------------------------------*/
980 floatx80
floatx80_twotox(floatx80 a
, float_status
*status
)
986 int8_t user_rnd_mode
, user_rnd_prec
;
988 int32_t compact
, n
, j
, l
, m
, m1
;
989 floatx80 fp0
, fp1
, fp2
, fp3
, adjfact
, fact1
, fact2
;
991 aSig
= extractFloatx80Frac(a
);
992 aExp
= extractFloatx80Exp(a
);
993 aSign
= extractFloatx80Sign(a
);
995 if (aExp
== 0x7FFF) {
996 if ((uint64_t) (aSig
<< 1)) {
997 return propagateFloatx80NaNOneArg(a
, status
);
1000 return packFloatx80(0, 0, 0);
1002 return packFloatx80(0, floatx80_infinity
.high
,
1003 floatx80_infinity
.low
);
1006 if (aExp
== 0 && aSig
== 0) {
1007 return packFloatx80(0, one_exp
, one_sig
);
1010 user_rnd_mode
= status
->float_rounding_mode
;
1011 user_rnd_prec
= status
->floatx80_rounding_precision
;
1012 status
->float_rounding_mode
= float_round_nearest_even
;
1013 status
->floatx80_rounding_precision
= 80;
1017 compact
= floatx80_make_compact(aExp
, aSig
);
1019 if (compact
< 0x3FB98000 || compact
> 0x400D80C0) {
1020 /* |X| > 16480 or |X| < 2^(-70) */
1021 if (compact
> 0x3FFF8000) { /* |X| > 16480 */
1022 status
->float_rounding_mode
= user_rnd_mode
;
1023 status
->floatx80_rounding_precision
= user_rnd_prec
;
1026 return roundAndPackFloatx80(status
->floatx80_rounding_precision
,
1027 0, -0x1000, aSig
, 0, status
);
1029 return roundAndPackFloatx80(status
->floatx80_rounding_precision
,
1030 0, 0x8000, aSig
, 0, status
);
1032 } else { /* |X| < 2^(-70) */
1033 status
->float_rounding_mode
= user_rnd_mode
;
1034 status
->floatx80_rounding_precision
= user_rnd_prec
;
1036 a
= floatx80_add(fp0
, float32_to_floatx80(
1037 make_float32(0x3F800000), status
),
1038 status
); /* 1 + X */
1040 float_raise(float_flag_inexact
, status
);
1044 } else { /* 2^(-70) <= |X| <= 16480 */
1046 fp1
= floatx80_mul(fp1
, float32_to_floatx80(
1047 make_float32(0x42800000), status
),
1048 status
); /* X * 64 */
1049 n
= floatx80_to_int32(fp1
, status
);
1050 fp1
= int32_to_floatx80(n
, status
);
1052 l
= n
/ 64; /* NOTE: this is really arithmetic right shift by 6 */
1054 /* arithmetic right shift is division and
1055 * round towards minus infinity
1059 m
= l
/ 2; /* NOTE: this is really arithmetic right shift by 1 */
1060 if (l
< 0 && (l
& 1)) {
1061 /* arithmetic right shift is division and
1062 * round towards minus infinity
1067 m1
+= 0x3FFF; /* ADJFACT IS 2^(M') */
1069 adjfact
= packFloatx80(0, m1
, one_sig
);
1070 fact1
= exp2_tbl
[j
];
1072 fact2
.high
= exp2_tbl2
[j
] >> 16;
1074 fact2
.low
= (uint64_t)(exp2_tbl2
[j
] & 0xFFFF);
1077 fp1
= floatx80_mul(fp1
, float32_to_floatx80(
1078 make_float32(0x3C800000), status
),
1079 status
); /* (1/64)*N */
1080 fp0
= floatx80_sub(fp0
, fp1
, status
); /* X - (1/64)*INT(64 X) */
1081 fp2
= packFloatx80(0, 0x3FFE, LIT64(0xB17217F7D1CF79AC)); /* LOG2 */
1082 fp0
= floatx80_mul(fp0
, fp2
, status
); /* R */
1085 fp1
= floatx80_mul(fp0
, fp0
, status
); /* S = R*R */
1086 fp2
= float64_to_floatx80(make_float64(0x3F56C16D6F7BD0B2),
1088 fp3
= float64_to_floatx80(make_float64(0x3F811112302C712C),
1090 fp2
= floatx80_mul(fp2
, fp1
, status
); /* S*A5 */
1091 fp3
= floatx80_mul(fp3
, fp1
, status
); /* S*A4 */
1092 fp2
= floatx80_add(fp2
, float64_to_floatx80(
1093 make_float64(0x3FA5555555554CC1), status
),
1094 status
); /* A3+S*A5 */
1095 fp3
= floatx80_add(fp3
, float64_to_floatx80(
1096 make_float64(0x3FC5555555554A54), status
),
1097 status
); /* A2+S*A4 */
1098 fp2
= floatx80_mul(fp2
, fp1
, status
); /* S*(A3+S*A5) */
1099 fp3
= floatx80_mul(fp3
, fp1
, status
); /* S*(A2+S*A4) */
1100 fp2
= floatx80_add(fp2
, float64_to_floatx80(
1101 make_float64(0x3FE0000000000000), status
),
1102 status
); /* A1+S*(A3+S*A5) */
1103 fp3
= floatx80_mul(fp3
, fp0
, status
); /* R*S*(A2+S*A4) */
1105 fp2
= floatx80_mul(fp2
, fp1
, status
); /* S*(A1+S*(A3+S*A5)) */
1106 fp0
= floatx80_add(fp0
, fp3
, status
); /* R+R*S*(A2+S*A4) */
1107 fp0
= floatx80_add(fp0
, fp2
, status
); /* EXP(R) - 1 */
1109 fp0
= floatx80_mul(fp0
, fact1
, status
);
1110 fp0
= floatx80_add(fp0
, fact2
, status
);
1111 fp0
= floatx80_add(fp0
, fact1
, status
);
1113 status
->float_rounding_mode
= user_rnd_mode
;
1114 status
->floatx80_rounding_precision
= user_rnd_prec
;
1116 a
= floatx80_mul(fp0
, adjfact
, status
);
1118 float_raise(float_flag_inexact
, status
);
1124 /*----------------------------------------------------------------------------
1126 *----------------------------------------------------------------------------*/
1128 floatx80
floatx80_tentox(floatx80 a
, float_status
*status
)
1134 int8_t user_rnd_mode
, user_rnd_prec
;
1136 int32_t compact
, n
, j
, l
, m
, m1
;
1137 floatx80 fp0
, fp1
, fp2
, fp3
, adjfact
, fact1
, fact2
;
1139 aSig
= extractFloatx80Frac(a
);
1140 aExp
= extractFloatx80Exp(a
);
1141 aSign
= extractFloatx80Sign(a
);
1143 if (aExp
== 0x7FFF) {
1144 if ((uint64_t) (aSig
<< 1)) {
1145 return propagateFloatx80NaNOneArg(a
, status
);
1148 return packFloatx80(0, 0, 0);
1150 return packFloatx80(0, floatx80_infinity
.high
,
1151 floatx80_infinity
.low
);
1154 if (aExp
== 0 && aSig
== 0) {
1155 return packFloatx80(0, one_exp
, one_sig
);
1158 user_rnd_mode
= status
->float_rounding_mode
;
1159 user_rnd_prec
= status
->floatx80_rounding_precision
;
1160 status
->float_rounding_mode
= float_round_nearest_even
;
1161 status
->floatx80_rounding_precision
= 80;
1165 compact
= floatx80_make_compact(aExp
, aSig
);
1167 if (compact
< 0x3FB98000 || compact
> 0x400B9B07) {
1168 /* |X| > 16480 LOG2/LOG10 or |X| < 2^(-70) */
1169 if (compact
> 0x3FFF8000) { /* |X| > 16480 */
1170 status
->float_rounding_mode
= user_rnd_mode
;
1171 status
->floatx80_rounding_precision
= user_rnd_prec
;
1174 return roundAndPackFloatx80(status
->floatx80_rounding_precision
,
1175 0, -0x1000, aSig
, 0, status
);
1177 return roundAndPackFloatx80(status
->floatx80_rounding_precision
,
1178 0, 0x8000, aSig
, 0, status
);
1180 } else { /* |X| < 2^(-70) */
1181 status
->float_rounding_mode
= user_rnd_mode
;
1182 status
->floatx80_rounding_precision
= user_rnd_prec
;
1184 a
= floatx80_add(fp0
, float32_to_floatx80(
1185 make_float32(0x3F800000), status
),
1186 status
); /* 1 + X */
1188 float_raise(float_flag_inexact
, status
);
1192 } else { /* 2^(-70) <= |X| <= 16480 LOG 2 / LOG 10 */
1194 fp1
= floatx80_mul(fp1
, float64_to_floatx80(
1195 make_float64(0x406A934F0979A371),
1196 status
), status
); /* X*64*LOG10/LOG2 */
1197 n
= floatx80_to_int32(fp1
, status
); /* N=INT(X*64*LOG10/LOG2) */
1198 fp1
= int32_to_floatx80(n
, status
);
1201 l
= n
/ 64; /* NOTE: this is really arithmetic right shift by 6 */
1203 /* arithmetic right shift is division and
1204 * round towards minus infinity
1208 m
= l
/ 2; /* NOTE: this is really arithmetic right shift by 1 */
1209 if (l
< 0 && (l
& 1)) {
1210 /* arithmetic right shift is division and
1211 * round towards minus infinity
1216 m1
+= 0x3FFF; /* ADJFACT IS 2^(M') */
1218 adjfact
= packFloatx80(0, m1
, one_sig
);
1219 fact1
= exp2_tbl
[j
];
1221 fact2
.high
= exp2_tbl2
[j
] >> 16;
1223 fact2
.low
= (uint64_t)(exp2_tbl2
[j
] & 0xFFFF);
1227 fp1
= floatx80_mul(fp1
, float64_to_floatx80(
1228 make_float64(0x3F734413509F8000), status
),
1229 status
); /* N*(LOG2/64LOG10)_LEAD */
1230 fp3
= packFloatx80(1, 0x3FCD, LIT64(0xC0219DC1DA994FD2));
1231 fp2
= floatx80_mul(fp2
, fp3
, status
); /* N*(LOG2/64LOG10)_TRAIL */
1232 fp0
= floatx80_sub(fp0
, fp1
, status
); /* X - N L_LEAD */
1233 fp0
= floatx80_sub(fp0
, fp2
, status
); /* X - N L_TRAIL */
1234 fp2
= packFloatx80(0, 0x4000, LIT64(0x935D8DDDAAA8AC17)); /* LOG10 */
1235 fp0
= floatx80_mul(fp0
, fp2
, status
); /* R */
1238 fp1
= floatx80_mul(fp0
, fp0
, status
); /* S = R*R */
1239 fp2
= float64_to_floatx80(make_float64(0x3F56C16D6F7BD0B2),
1241 fp3
= float64_to_floatx80(make_float64(0x3F811112302C712C),
1243 fp2
= floatx80_mul(fp2
, fp1
, status
); /* S*A5 */
1244 fp3
= floatx80_mul(fp3
, fp1
, status
); /* S*A4 */
1245 fp2
= floatx80_add(fp2
, float64_to_floatx80(
1246 make_float64(0x3FA5555555554CC1), status
),
1247 status
); /* A3+S*A5 */
1248 fp3
= floatx80_add(fp3
, float64_to_floatx80(
1249 make_float64(0x3FC5555555554A54), status
),
1250 status
); /* A2+S*A4 */
1251 fp2
= floatx80_mul(fp2
, fp1
, status
); /* S*(A3+S*A5) */
1252 fp3
= floatx80_mul(fp3
, fp1
, status
); /* S*(A2+S*A4) */
1253 fp2
= floatx80_add(fp2
, float64_to_floatx80(
1254 make_float64(0x3FE0000000000000), status
),
1255 status
); /* A1+S*(A3+S*A5) */
1256 fp3
= floatx80_mul(fp3
, fp0
, status
); /* R*S*(A2+S*A4) */
1258 fp2
= floatx80_mul(fp2
, fp1
, status
); /* S*(A1+S*(A3+S*A5)) */
1259 fp0
= floatx80_add(fp0
, fp3
, status
); /* R+R*S*(A2+S*A4) */
1260 fp0
= floatx80_add(fp0
, fp2
, status
); /* EXP(R) - 1 */
1262 fp0
= floatx80_mul(fp0
, fact1
, status
);
1263 fp0
= floatx80_add(fp0
, fact2
, status
);
1264 fp0
= floatx80_add(fp0
, fact1
, status
);
1266 status
->float_rounding_mode
= user_rnd_mode
;
1267 status
->floatx80_rounding_precision
= user_rnd_prec
;
1269 a
= floatx80_mul(fp0
, adjfact
, status
);
1271 float_raise(float_flag_inexact
, status
);
1277 /*----------------------------------------------------------------------------
1279 *----------------------------------------------------------------------------*/
1281 floatx80
floatx80_tan(floatx80 a
, float_status
*status
)
1285 uint64_t aSig
, xSig
;
1287 int8_t user_rnd_mode
, user_rnd_prec
;
1289 int32_t compact
, l
, n
, j
;
1290 floatx80 fp0
, fp1
, fp2
, fp3
, fp4
, fp5
, invtwopi
, twopi1
, twopi2
;
1294 aSig
= extractFloatx80Frac(a
);
1295 aExp
= extractFloatx80Exp(a
);
1296 aSign
= extractFloatx80Sign(a
);
1298 if (aExp
== 0x7FFF) {
1299 if ((uint64_t) (aSig
<< 1)) {
1300 return propagateFloatx80NaNOneArg(a
, status
);
1302 float_raise(float_flag_invalid
, status
);
1303 return floatx80_default_nan(status
);
1306 if (aExp
== 0 && aSig
== 0) {
1307 return packFloatx80(aSign
, 0, 0);
1310 user_rnd_mode
= status
->float_rounding_mode
;
1311 user_rnd_prec
= status
->floatx80_rounding_precision
;
1312 status
->float_rounding_mode
= float_round_nearest_even
;
1313 status
->floatx80_rounding_precision
= 80;
1315 compact
= floatx80_make_compact(aExp
, aSig
);
1319 if (compact
< 0x3FD78000 || compact
> 0x4004BC7E) {
1320 /* 2^(-40) > |X| > 15 PI */
1321 if (compact
> 0x3FFF8000) { /* |X| >= 15 PI */
1323 fp1
= packFloatx80(0, 0, 0);
1324 if (compact
== 0x7FFEFFFF) {
1325 twopi1
= packFloatx80(aSign
^ 1, 0x7FFE,
1326 LIT64(0xC90FDAA200000000));
1327 twopi2
= packFloatx80(aSign
^ 1, 0x7FDC,
1328 LIT64(0x85A308D300000000));
1329 fp0
= floatx80_add(fp0
, twopi1
, status
);
1331 fp0
= floatx80_add(fp0
, twopi2
, status
);
1332 fp1
= floatx80_sub(fp1
, fp0
, status
);
1333 fp1
= floatx80_add(fp1
, twopi2
, status
);
1336 xSign
= extractFloatx80Sign(fp0
);
1337 xExp
= extractFloatx80Exp(fp0
);
1346 invtwopi
= packFloatx80(0, 0x3FFE - l
,
1347 LIT64(0xA2F9836E4E44152A)); /* INVTWOPI */
1348 twopi1
= packFloatx80(0, 0x3FFF + l
, LIT64(0xC90FDAA200000000));
1349 twopi2
= packFloatx80(0, 0x3FDD + l
, LIT64(0x85A308D300000000));
1351 /* SIGN(INARG)*2^63 IN SGL */
1352 twoto63
= packFloat32(xSign
, 0xBE, 0);
1354 fp2
= floatx80_mul(fp0
, invtwopi
, status
);
1355 fp2
= floatx80_add(fp2
, float32_to_floatx80(twoto63
, status
),
1356 status
); /* THE FRACT PART OF FP2 IS ROUNDED */
1357 fp2
= floatx80_sub(fp2
, float32_to_floatx80(twoto63
, status
),
1358 status
); /* FP2 is N */
1359 fp4
= floatx80_mul(twopi1
, fp2
, status
); /* W = N*P1 */
1360 fp5
= floatx80_mul(twopi2
, fp2
, status
); /* w = N*P2 */
1361 fp3
= floatx80_add(fp4
, fp5
, status
); /* FP3 is P */
1362 fp4
= floatx80_sub(fp4
, fp3
, status
); /* W-P */
1363 fp0
= floatx80_sub(fp0
, fp3
, status
); /* FP0 is A := R - P */
1364 fp4
= floatx80_add(fp4
, fp5
, status
); /* FP4 is p = (W-P)+w */
1365 fp3
= fp0
; /* FP3 is A */
1366 fp1
= floatx80_sub(fp1
, fp4
, status
); /* FP1 is a := r - p */
1367 fp0
= floatx80_add(fp0
, fp1
, status
); /* FP0 is R := A+a */
1370 n
= floatx80_to_int32(fp2
, status
);
1373 fp3
= floatx80_sub(fp3
, fp0
, status
); /* A-R */
1374 fp1
= floatx80_add(fp1
, fp3
, status
); /* FP1 is r := (A-R)+a */
1377 status
->float_rounding_mode
= user_rnd_mode
;
1378 status
->floatx80_rounding_precision
= user_rnd_prec
;
1380 a
= floatx80_move(a
, status
);
1382 float_raise(float_flag_inexact
, status
);
1387 fp1
= floatx80_mul(fp0
, float64_to_floatx80(
1388 make_float64(0x3FE45F306DC9C883), status
),
1389 status
); /* X*2/PI */
1391 n
= floatx80_to_int32(fp1
, status
);
1394 fp0
= floatx80_sub(fp0
, pi_tbl
[j
], status
); /* X-Y1 */
1395 fp0
= floatx80_sub(fp0
, float32_to_floatx80(pi_tbl2
[j
], status
),
1396 status
); /* FP0 IS R = (X-Y1)-Y2 */
1402 fp0
= floatx80_mul(fp0
, fp0
, status
); /* S = R*R */
1403 fp3
= float64_to_floatx80(make_float64(0x3EA0B759F50F8688),
1405 fp2
= float64_to_floatx80(make_float64(0xBEF2BAA5A8924F04),
1407 fp3
= floatx80_mul(fp3
, fp0
, status
); /* SQ4 */
1408 fp2
= floatx80_mul(fp2
, fp0
, status
); /* SP3 */
1409 fp3
= floatx80_add(fp3
, float64_to_floatx80(
1410 make_float64(0xBF346F59B39BA65F), status
),
1411 status
); /* Q3+SQ4 */
1412 fp4
= packFloatx80(0, 0x3FF6, LIT64(0xE073D3FC199C4A00));
1413 fp2
= floatx80_add(fp2
, fp4
, status
); /* P2+SP3 */
1414 fp3
= floatx80_mul(fp3
, fp0
, status
); /* S(Q3+SQ4) */
1415 fp2
= floatx80_mul(fp2
, fp0
, status
); /* S(P2+SP3) */
1416 fp4
= packFloatx80(0, 0x3FF9, LIT64(0xD23CD68415D95FA1));
1417 fp3
= floatx80_add(fp3
, fp4
, status
); /* Q2+S(Q3+SQ4) */
1418 fp4
= packFloatx80(1, 0x3FFC, LIT64(0x8895A6C5FB423BCA));
1419 fp2
= floatx80_add(fp2
, fp4
, status
); /* P1+S(P2+SP3) */
1420 fp3
= floatx80_mul(fp3
, fp0
, status
); /* S(Q2+S(Q3+SQ4)) */
1421 fp2
= floatx80_mul(fp2
, fp0
, status
); /* S(P1+S(P2+SP3)) */
1422 fp4
= packFloatx80(1, 0x3FFD, LIT64(0xEEF57E0DA84BC8CE));
1423 fp3
= floatx80_add(fp3
, fp4
, status
); /* Q1+S(Q2+S(Q3+SQ4)) */
1424 fp2
= floatx80_mul(fp2
, fp1
, status
); /* RS(P1+S(P2+SP3)) */
1425 fp0
= floatx80_mul(fp0
, fp3
, status
); /* S(Q1+S(Q2+S(Q3+SQ4))) */
1426 fp1
= floatx80_add(fp1
, fp2
, status
); /* R+RS(P1+S(P2+SP3)) */
1427 fp0
= floatx80_add(fp0
, float32_to_floatx80(
1428 make_float32(0x3F800000), status
),
1429 status
); /* 1+S(Q1+S(Q2+S(Q3+SQ4))) */
1431 xSign
= extractFloatx80Sign(fp1
);
1432 xExp
= extractFloatx80Exp(fp1
);
1433 xSig
= extractFloatx80Frac(fp1
);
1435 fp1
= packFloatx80(xSign
, xExp
, xSig
);
1437 status
->float_rounding_mode
= user_rnd_mode
;
1438 status
->floatx80_rounding_precision
= user_rnd_prec
;
1440 a
= floatx80_div(fp0
, fp1
, status
);
1442 float_raise(float_flag_inexact
, status
);
1446 fp1
= floatx80_mul(fp0
, fp0
, status
); /* S = R*R */
1447 fp3
= float64_to_floatx80(make_float64(0x3EA0B759F50F8688),
1449 fp2
= float64_to_floatx80(make_float64(0xBEF2BAA5A8924F04),
1451 fp3
= floatx80_mul(fp3
, fp1
, status
); /* SQ4 */
1452 fp2
= floatx80_mul(fp2
, fp1
, status
); /* SP3 */
1453 fp3
= floatx80_add(fp3
, float64_to_floatx80(
1454 make_float64(0xBF346F59B39BA65F), status
),
1455 status
); /* Q3+SQ4 */
1456 fp4
= packFloatx80(0, 0x3FF6, LIT64(0xE073D3FC199C4A00));
1457 fp2
= floatx80_add(fp2
, fp4
, status
); /* P2+SP3 */
1458 fp3
= floatx80_mul(fp3
, fp1
, status
); /* S(Q3+SQ4) */
1459 fp2
= floatx80_mul(fp2
, fp1
, status
); /* S(P2+SP3) */
1460 fp4
= packFloatx80(0, 0x3FF9, LIT64(0xD23CD68415D95FA1));
1461 fp3
= floatx80_add(fp3
, fp4
, status
); /* Q2+S(Q3+SQ4) */
1462 fp4
= packFloatx80(1, 0x3FFC, LIT64(0x8895A6C5FB423BCA));
1463 fp2
= floatx80_add(fp2
, fp4
, status
); /* P1+S(P2+SP3) */
1464 fp3
= floatx80_mul(fp3
, fp1
, status
); /* S(Q2+S(Q3+SQ4)) */
1465 fp2
= floatx80_mul(fp2
, fp1
, status
); /* S(P1+S(P2+SP3)) */
1466 fp4
= packFloatx80(1, 0x3FFD, LIT64(0xEEF57E0DA84BC8CE));
1467 fp3
= floatx80_add(fp3
, fp4
, status
); /* Q1+S(Q2+S(Q3+SQ4)) */
1468 fp2
= floatx80_mul(fp2
, fp0
, status
); /* RS(P1+S(P2+SP3)) */
1469 fp1
= floatx80_mul(fp1
, fp3
, status
); /* S(Q1+S(Q2+S(Q3+SQ4))) */
1470 fp0
= floatx80_add(fp0
, fp2
, status
); /* R+RS(P1+S(P2+SP3)) */
1471 fp1
= floatx80_add(fp1
, float32_to_floatx80(
1472 make_float32(0x3F800000), status
),
1473 status
); /* 1+S(Q1+S(Q2+S(Q3+SQ4))) */
1475 status
->float_rounding_mode
= user_rnd_mode
;
1476 status
->floatx80_rounding_precision
= user_rnd_prec
;
1478 a
= floatx80_div(fp0
, fp1
, status
);
1480 float_raise(float_flag_inexact
, status
);
1487 /*----------------------------------------------------------------------------
1489 *----------------------------------------------------------------------------*/
1491 floatx80
floatx80_sin(floatx80 a
, float_status
*status
)
1495 uint64_t aSig
, xSig
;
1497 int8_t user_rnd_mode
, user_rnd_prec
;
1499 int32_t compact
, l
, n
, j
;
1500 floatx80 fp0
, fp1
, fp2
, fp3
, fp4
, fp5
, x
, invtwopi
, twopi1
, twopi2
;
1501 float32 posneg1
, twoto63
;
1504 aSig
= extractFloatx80Frac(a
);
1505 aExp
= extractFloatx80Exp(a
);
1506 aSign
= extractFloatx80Sign(a
);
1508 if (aExp
== 0x7FFF) {
1509 if ((uint64_t) (aSig
<< 1)) {
1510 return propagateFloatx80NaNOneArg(a
, status
);
1512 float_raise(float_flag_invalid
, status
);
1513 return floatx80_default_nan(status
);
1516 if (aExp
== 0 && aSig
== 0) {
1517 return packFloatx80(aSign
, 0, 0);
1520 user_rnd_mode
= status
->float_rounding_mode
;
1521 user_rnd_prec
= status
->floatx80_rounding_precision
;
1522 status
->float_rounding_mode
= float_round_nearest_even
;
1523 status
->floatx80_rounding_precision
= 80;
1525 compact
= floatx80_make_compact(aExp
, aSig
);
1529 if (compact
< 0x3FD78000 || compact
> 0x4004BC7E) {
1530 /* 2^(-40) > |X| > 15 PI */
1531 if (compact
> 0x3FFF8000) { /* |X| >= 15 PI */
1533 fp1
= packFloatx80(0, 0, 0);
1534 if (compact
== 0x7FFEFFFF) {
1535 twopi1
= packFloatx80(aSign
^ 1, 0x7FFE,
1536 LIT64(0xC90FDAA200000000));
1537 twopi2
= packFloatx80(aSign
^ 1, 0x7FDC,
1538 LIT64(0x85A308D300000000));
1539 fp0
= floatx80_add(fp0
, twopi1
, status
);
1541 fp0
= floatx80_add(fp0
, twopi2
, status
);
1542 fp1
= floatx80_sub(fp1
, fp0
, status
);
1543 fp1
= floatx80_add(fp1
, twopi2
, status
);
1546 xSign
= extractFloatx80Sign(fp0
);
1547 xExp
= extractFloatx80Exp(fp0
);
1556 invtwopi
= packFloatx80(0, 0x3FFE - l
,
1557 LIT64(0xA2F9836E4E44152A)); /* INVTWOPI */
1558 twopi1
= packFloatx80(0, 0x3FFF + l
, LIT64(0xC90FDAA200000000));
1559 twopi2
= packFloatx80(0, 0x3FDD + l
, LIT64(0x85A308D300000000));
1561 /* SIGN(INARG)*2^63 IN SGL */
1562 twoto63
= packFloat32(xSign
, 0xBE, 0);
1564 fp2
= floatx80_mul(fp0
, invtwopi
, status
);
1565 fp2
= floatx80_add(fp2
, float32_to_floatx80(twoto63
, status
),
1566 status
); /* THE FRACT PART OF FP2 IS ROUNDED */
1567 fp2
= floatx80_sub(fp2
, float32_to_floatx80(twoto63
, status
),
1568 status
); /* FP2 is N */
1569 fp4
= floatx80_mul(twopi1
, fp2
, status
); /* W = N*P1 */
1570 fp5
= floatx80_mul(twopi2
, fp2
, status
); /* w = N*P2 */
1571 fp3
= floatx80_add(fp4
, fp5
, status
); /* FP3 is P */
1572 fp4
= floatx80_sub(fp4
, fp3
, status
); /* W-P */
1573 fp0
= floatx80_sub(fp0
, fp3
, status
); /* FP0 is A := R - P */
1574 fp4
= floatx80_add(fp4
, fp5
, status
); /* FP4 is p = (W-P)+w */
1575 fp3
= fp0
; /* FP3 is A */
1576 fp1
= floatx80_sub(fp1
, fp4
, status
); /* FP1 is a := r - p */
1577 fp0
= floatx80_add(fp0
, fp1
, status
); /* FP0 is R := A+a */
1580 n
= floatx80_to_int32(fp2
, status
);
1583 fp3
= floatx80_sub(fp3
, fp0
, status
); /* A-R */
1584 fp1
= floatx80_add(fp1
, fp3
, status
); /* FP1 is r := (A-R)+a */
1588 fp0
= float32_to_floatx80(make_float32(0x3F800000),
1591 status
->float_rounding_mode
= user_rnd_mode
;
1592 status
->floatx80_rounding_precision
= user_rnd_prec
;
1595 a
= floatx80_move(a
, status
);
1596 float_raise(float_flag_inexact
, status
);
1601 fp1
= floatx80_mul(fp0
, float64_to_floatx80(
1602 make_float64(0x3FE45F306DC9C883), status
),
1603 status
); /* X*2/PI */
1605 n
= floatx80_to_int32(fp1
, status
);
1608 fp0
= floatx80_sub(fp0
, pi_tbl
[j
], status
); /* X-Y1 */
1609 fp0
= floatx80_sub(fp0
, float32_to_floatx80(pi_tbl2
[j
], status
),
1610 status
); /* FP0 IS R = (X-Y1)-Y2 */
1615 fp0
= floatx80_mul(fp0
, fp0
, status
); /* FP0 IS S */
1616 fp1
= floatx80_mul(fp0
, fp0
, status
); /* FP1 IS T */
1617 fp2
= float64_to_floatx80(make_float64(0x3D2AC4D0D6011EE3),
1619 fp3
= float64_to_floatx80(make_float64(0xBDA9396F9F45AC19),
1622 xSign
= extractFloatx80Sign(fp0
); /* X IS S */
1623 xExp
= extractFloatx80Exp(fp0
);
1624 xSig
= extractFloatx80Frac(fp0
);
1628 posneg1
= make_float32(0xBF800000); /* -1 */
1631 posneg1
= make_float32(0x3F800000); /* 1 */
1632 } /* X IS NOW R'= SGN*R */
1634 fp2
= floatx80_mul(fp2
, fp1
, status
); /* TB8 */
1635 fp3
= floatx80_mul(fp3
, fp1
, status
); /* TB7 */
1636 fp2
= floatx80_add(fp2
, float64_to_floatx80(
1637 make_float64(0x3E21EED90612C972), status
),
1638 status
); /* B6+TB8 */
1639 fp3
= floatx80_add(fp3
, float64_to_floatx80(
1640 make_float64(0xBE927E4FB79D9FCF), status
),
1641 status
); /* B5+TB7 */
1642 fp2
= floatx80_mul(fp2
, fp1
, status
); /* T(B6+TB8) */
1643 fp3
= floatx80_mul(fp3
, fp1
, status
); /* T(B5+TB7) */
1644 fp2
= floatx80_add(fp2
, float64_to_floatx80(
1645 make_float64(0x3EFA01A01A01D423), status
),
1646 status
); /* B4+T(B6+TB8) */
1647 fp4
= packFloatx80(1, 0x3FF5, LIT64(0xB60B60B60B61D438));
1648 fp3
= floatx80_add(fp3
, fp4
, status
); /* B3+T(B5+TB7) */
1649 fp2
= floatx80_mul(fp2
, fp1
, status
); /* T(B4+T(B6+TB8)) */
1650 fp1
= floatx80_mul(fp1
, fp3
, status
); /* T(B3+T(B5+TB7)) */
1651 fp4
= packFloatx80(0, 0x3FFA, LIT64(0xAAAAAAAAAAAAAB5E));
1652 fp2
= floatx80_add(fp2
, fp4
, status
); /* B2+T(B4+T(B6+TB8)) */
1653 fp1
= floatx80_add(fp1
, float32_to_floatx80(
1654 make_float32(0xBF000000), status
),
1655 status
); /* B1+T(B3+T(B5+TB7)) */
1656 fp0
= floatx80_mul(fp0
, fp2
, status
); /* S(B2+T(B4+T(B6+TB8))) */
1657 fp0
= floatx80_add(fp0
, fp1
, status
); /* [B1+T(B3+T(B5+TB7))]+
1658 * [S(B2+T(B4+T(B6+TB8)))]
1661 x
= packFloatx80(xSign
, xExp
, xSig
);
1662 fp0
= floatx80_mul(fp0
, x
, status
);
1664 status
->float_rounding_mode
= user_rnd_mode
;
1665 status
->floatx80_rounding_precision
= user_rnd_prec
;
1667 a
= floatx80_add(fp0
, float32_to_floatx80(posneg1
, status
), status
);
1669 float_raise(float_flag_inexact
, status
);
1674 xSign
= extractFloatx80Sign(fp0
); /* X IS R */
1675 xExp
= extractFloatx80Exp(fp0
);
1676 xSig
= extractFloatx80Frac(fp0
);
1678 xSign
^= (n
>> 1) & 1; /* X IS NOW R'= SGN*R */
1680 fp0
= floatx80_mul(fp0
, fp0
, status
); /* FP0 IS S */
1681 fp1
= floatx80_mul(fp0
, fp0
, status
); /* FP1 IS T */
1682 fp3
= float64_to_floatx80(make_float64(0xBD6AAA77CCC994F5),
1684 fp2
= float64_to_floatx80(make_float64(0x3DE612097AAE8DA1),
1686 fp3
= floatx80_mul(fp3
, fp1
, status
); /* T*A7 */
1687 fp2
= floatx80_mul(fp2
, fp1
, status
); /* T*A6 */
1688 fp3
= floatx80_add(fp3
, float64_to_floatx80(
1689 make_float64(0xBE5AE6452A118AE4), status
),
1690 status
); /* A5+T*A7 */
1691 fp2
= floatx80_add(fp2
, float64_to_floatx80(
1692 make_float64(0x3EC71DE3A5341531), status
),
1693 status
); /* A4+T*A6 */
1694 fp3
= floatx80_mul(fp3
, fp1
, status
); /* T(A5+TA7) */
1695 fp2
= floatx80_mul(fp2
, fp1
, status
); /* T(A4+TA6) */
1696 fp3
= floatx80_add(fp3
, float64_to_floatx80(
1697 make_float64(0xBF2A01A01A018B59), status
),
1698 status
); /* A3+T(A5+TA7) */
1699 fp4
= packFloatx80(0, 0x3FF8, LIT64(0x88888888888859AF));
1700 fp2
= floatx80_add(fp2
, fp4
, status
); /* A2+T(A4+TA6) */
1701 fp1
= floatx80_mul(fp1
, fp3
, status
); /* T(A3+T(A5+TA7)) */
1702 fp2
= floatx80_mul(fp2
, fp0
, status
); /* S(A2+T(A4+TA6)) */
1703 fp4
= packFloatx80(1, 0x3FFC, LIT64(0xAAAAAAAAAAAAAA99));
1704 fp1
= floatx80_add(fp1
, fp4
, status
); /* A1+T(A3+T(A5+TA7)) */
1705 fp1
= floatx80_add(fp1
, fp2
,
1706 status
); /* [A1+T(A3+T(A5+TA7))]+
1710 x
= packFloatx80(xSign
, xExp
, xSig
);
1711 fp0
= floatx80_mul(fp0
, x
, status
); /* R'*S */
1712 fp0
= floatx80_mul(fp0
, fp1
, status
); /* SIN(R')-R' */
1714 status
->float_rounding_mode
= user_rnd_mode
;
1715 status
->floatx80_rounding_precision
= user_rnd_prec
;
1717 a
= floatx80_add(fp0
, x
, status
);
1719 float_raise(float_flag_inexact
, status
);
1726 /*----------------------------------------------------------------------------
1728 *----------------------------------------------------------------------------*/
1730 floatx80
floatx80_cos(floatx80 a
, float_status
*status
)
1734 uint64_t aSig
, xSig
;
1736 int8_t user_rnd_mode
, user_rnd_prec
;
1738 int32_t compact
, l
, n
, j
;
1739 floatx80 fp0
, fp1
, fp2
, fp3
, fp4
, fp5
, x
, invtwopi
, twopi1
, twopi2
;
1740 float32 posneg1
, twoto63
;
1743 aSig
= extractFloatx80Frac(a
);
1744 aExp
= extractFloatx80Exp(a
);
1745 aSign
= extractFloatx80Sign(a
);
1747 if (aExp
== 0x7FFF) {
1748 if ((uint64_t) (aSig
<< 1)) {
1749 return propagateFloatx80NaNOneArg(a
, status
);
1751 float_raise(float_flag_invalid
, status
);
1752 return floatx80_default_nan(status
);
1755 if (aExp
== 0 && aSig
== 0) {
1756 return packFloatx80(0, one_exp
, one_sig
);
1759 user_rnd_mode
= status
->float_rounding_mode
;
1760 user_rnd_prec
= status
->floatx80_rounding_precision
;
1761 status
->float_rounding_mode
= float_round_nearest_even
;
1762 status
->floatx80_rounding_precision
= 80;
1764 compact
= floatx80_make_compact(aExp
, aSig
);
1768 if (compact
< 0x3FD78000 || compact
> 0x4004BC7E) {
1769 /* 2^(-40) > |X| > 15 PI */
1770 if (compact
> 0x3FFF8000) { /* |X| >= 15 PI */
1772 fp1
= packFloatx80(0, 0, 0);
1773 if (compact
== 0x7FFEFFFF) {
1774 twopi1
= packFloatx80(aSign
^ 1, 0x7FFE,
1775 LIT64(0xC90FDAA200000000));
1776 twopi2
= packFloatx80(aSign
^ 1, 0x7FDC,
1777 LIT64(0x85A308D300000000));
1778 fp0
= floatx80_add(fp0
, twopi1
, status
);
1780 fp0
= floatx80_add(fp0
, twopi2
, status
);
1781 fp1
= floatx80_sub(fp1
, fp0
, status
);
1782 fp1
= floatx80_add(fp1
, twopi2
, status
);
1785 xSign
= extractFloatx80Sign(fp0
);
1786 xExp
= extractFloatx80Exp(fp0
);
1795 invtwopi
= packFloatx80(0, 0x3FFE - l
,
1796 LIT64(0xA2F9836E4E44152A)); /* INVTWOPI */
1797 twopi1
= packFloatx80(0, 0x3FFF + l
, LIT64(0xC90FDAA200000000));
1798 twopi2
= packFloatx80(0, 0x3FDD + l
, LIT64(0x85A308D300000000));
1800 /* SIGN(INARG)*2^63 IN SGL */
1801 twoto63
= packFloat32(xSign
, 0xBE, 0);
1803 fp2
= floatx80_mul(fp0
, invtwopi
, status
);
1804 fp2
= floatx80_add(fp2
, float32_to_floatx80(twoto63
, status
),
1805 status
); /* THE FRACT PART OF FP2 IS ROUNDED */
1806 fp2
= floatx80_sub(fp2
, float32_to_floatx80(twoto63
, status
),
1807 status
); /* FP2 is N */
1808 fp4
= floatx80_mul(twopi1
, fp2
, status
); /* W = N*P1 */
1809 fp5
= floatx80_mul(twopi2
, fp2
, status
); /* w = N*P2 */
1810 fp3
= floatx80_add(fp4
, fp5
, status
); /* FP3 is P */
1811 fp4
= floatx80_sub(fp4
, fp3
, status
); /* W-P */
1812 fp0
= floatx80_sub(fp0
, fp3
, status
); /* FP0 is A := R - P */
1813 fp4
= floatx80_add(fp4
, fp5
, status
); /* FP4 is p = (W-P)+w */
1814 fp3
= fp0
; /* FP3 is A */
1815 fp1
= floatx80_sub(fp1
, fp4
, status
); /* FP1 is a := r - p */
1816 fp0
= floatx80_add(fp0
, fp1
, status
); /* FP0 is R := A+a */
1819 n
= floatx80_to_int32(fp2
, status
);
1822 fp3
= floatx80_sub(fp3
, fp0
, status
); /* A-R */
1823 fp1
= floatx80_add(fp1
, fp3
, status
); /* FP1 is r := (A-R)+a */
1827 fp0
= float32_to_floatx80(make_float32(0x3F800000), status
); /* 1 */
1829 status
->float_rounding_mode
= user_rnd_mode
;
1830 status
->floatx80_rounding_precision
= user_rnd_prec
;
1833 a
= floatx80_sub(fp0
, float32_to_floatx80(
1834 make_float32(0x00800000), status
),
1836 float_raise(float_flag_inexact
, status
);
1841 fp1
= floatx80_mul(fp0
, float64_to_floatx80(
1842 make_float64(0x3FE45F306DC9C883), status
),
1843 status
); /* X*2/PI */
1845 n
= floatx80_to_int32(fp1
, status
);
1848 fp0
= floatx80_sub(fp0
, pi_tbl
[j
], status
); /* X-Y1 */
1849 fp0
= floatx80_sub(fp0
, float32_to_floatx80(pi_tbl2
[j
], status
),
1850 status
); /* FP0 IS R = (X-Y1)-Y2 */
1855 fp0
= floatx80_mul(fp0
, fp0
, status
); /* FP0 IS S */
1856 fp1
= floatx80_mul(fp0
, fp0
, status
); /* FP1 IS T */
1857 fp2
= float64_to_floatx80(make_float64(0x3D2AC4D0D6011EE3),
1859 fp3
= float64_to_floatx80(make_float64(0xBDA9396F9F45AC19),
1862 xSign
= extractFloatx80Sign(fp0
); /* X IS S */
1863 xExp
= extractFloatx80Exp(fp0
);
1864 xSig
= extractFloatx80Frac(fp0
);
1866 if (((n
+ 1) >> 1) & 1) {
1868 posneg1
= make_float32(0xBF800000); /* -1 */
1871 posneg1
= make_float32(0x3F800000); /* 1 */
1872 } /* X IS NOW R'= SGN*R */
1874 fp2
= floatx80_mul(fp2
, fp1
, status
); /* TB8 */
1875 fp3
= floatx80_mul(fp3
, fp1
, status
); /* TB7 */
1876 fp2
= floatx80_add(fp2
, float64_to_floatx80(
1877 make_float64(0x3E21EED90612C972), status
),
1878 status
); /* B6+TB8 */
1879 fp3
= floatx80_add(fp3
, float64_to_floatx80(
1880 make_float64(0xBE927E4FB79D9FCF), status
),
1881 status
); /* B5+TB7 */
1882 fp2
= floatx80_mul(fp2
, fp1
, status
); /* T(B6+TB8) */
1883 fp3
= floatx80_mul(fp3
, fp1
, status
); /* T(B5+TB7) */
1884 fp2
= floatx80_add(fp2
, float64_to_floatx80(
1885 make_float64(0x3EFA01A01A01D423), status
),
1886 status
); /* B4+T(B6+TB8) */
1887 fp4
= packFloatx80(1, 0x3FF5, LIT64(0xB60B60B60B61D438));
1888 fp3
= floatx80_add(fp3
, fp4
, status
); /* B3+T(B5+TB7) */
1889 fp2
= floatx80_mul(fp2
, fp1
, status
); /* T(B4+T(B6+TB8)) */
1890 fp1
= floatx80_mul(fp1
, fp3
, status
); /* T(B3+T(B5+TB7)) */
1891 fp4
= packFloatx80(0, 0x3FFA, LIT64(0xAAAAAAAAAAAAAB5E));
1892 fp2
= floatx80_add(fp2
, fp4
, status
); /* B2+T(B4+T(B6+TB8)) */
1893 fp1
= floatx80_add(fp1
, float32_to_floatx80(
1894 make_float32(0xBF000000), status
),
1895 status
); /* B1+T(B3+T(B5+TB7)) */
1896 fp0
= floatx80_mul(fp0
, fp2
, status
); /* S(B2+T(B4+T(B6+TB8))) */
1897 fp0
= floatx80_add(fp0
, fp1
, status
);
1898 /* [B1+T(B3+T(B5+TB7))]+[S(B2+T(B4+T(B6+TB8)))] */
1900 x
= packFloatx80(xSign
, xExp
, xSig
);
1901 fp0
= floatx80_mul(fp0
, x
, status
);
1903 status
->float_rounding_mode
= user_rnd_mode
;
1904 status
->floatx80_rounding_precision
= user_rnd_prec
;
1906 a
= floatx80_add(fp0
, float32_to_floatx80(posneg1
, status
), status
);
1908 float_raise(float_flag_inexact
, status
);
1913 xSign
= extractFloatx80Sign(fp0
); /* X IS R */
1914 xExp
= extractFloatx80Exp(fp0
);
1915 xSig
= extractFloatx80Frac(fp0
);
1917 xSign
^= ((n
+ 1) >> 1) & 1; /* X IS NOW R'= SGN*R */
1919 fp0
= floatx80_mul(fp0
, fp0
, status
); /* FP0 IS S */
1920 fp1
= floatx80_mul(fp0
, fp0
, status
); /* FP1 IS T */
1921 fp3
= float64_to_floatx80(make_float64(0xBD6AAA77CCC994F5),
1923 fp2
= float64_to_floatx80(make_float64(0x3DE612097AAE8DA1),
1925 fp3
= floatx80_mul(fp3
, fp1
, status
); /* T*A7 */
1926 fp2
= floatx80_mul(fp2
, fp1
, status
); /* T*A6 */
1927 fp3
= floatx80_add(fp3
, float64_to_floatx80(
1928 make_float64(0xBE5AE6452A118AE4), status
),
1929 status
); /* A5+T*A7 */
1930 fp2
= floatx80_add(fp2
, float64_to_floatx80(
1931 make_float64(0x3EC71DE3A5341531), status
),
1932 status
); /* A4+T*A6 */
1933 fp3
= floatx80_mul(fp3
, fp1
, status
); /* T(A5+TA7) */
1934 fp2
= floatx80_mul(fp2
, fp1
, status
); /* T(A4+TA6) */
1935 fp3
= floatx80_add(fp3
, float64_to_floatx80(
1936 make_float64(0xBF2A01A01A018B59), status
),
1937 status
); /* A3+T(A5+TA7) */
1938 fp4
= packFloatx80(0, 0x3FF8, LIT64(0x88888888888859AF));
1939 fp2
= floatx80_add(fp2
, fp4
, status
); /* A2+T(A4+TA6) */
1940 fp1
= floatx80_mul(fp1
, fp3
, status
); /* T(A3+T(A5+TA7)) */
1941 fp2
= floatx80_mul(fp2
, fp0
, status
); /* S(A2+T(A4+TA6)) */
1942 fp4
= packFloatx80(1, 0x3FFC, LIT64(0xAAAAAAAAAAAAAA99));
1943 fp1
= floatx80_add(fp1
, fp4
, status
); /* A1+T(A3+T(A5+TA7)) */
1944 fp1
= floatx80_add(fp1
, fp2
, status
);
1945 /* [A1+T(A3+T(A5+TA7))]+[S(A2+T(A4+TA6))] */
1947 x
= packFloatx80(xSign
, xExp
, xSig
);
1948 fp0
= floatx80_mul(fp0
, x
, status
); /* R'*S */
1949 fp0
= floatx80_mul(fp0
, fp1
, status
); /* SIN(R')-R' */
1951 status
->float_rounding_mode
= user_rnd_mode
;
1952 status
->floatx80_rounding_precision
= user_rnd_prec
;
1954 a
= floatx80_add(fp0
, x
, status
);
1956 float_raise(float_flag_inexact
, status
);
1963 /*----------------------------------------------------------------------------
1965 *----------------------------------------------------------------------------*/
1967 floatx80
floatx80_atan(floatx80 a
, float_status
*status
)
1973 int8_t user_rnd_mode
, user_rnd_prec
;
1975 int32_t compact
, tbl_index
;
1976 floatx80 fp0
, fp1
, fp2
, fp3
, xsave
;
1978 aSig
= extractFloatx80Frac(a
);
1979 aExp
= extractFloatx80Exp(a
);
1980 aSign
= extractFloatx80Sign(a
);
1982 if (aExp
== 0x7FFF) {
1983 if ((uint64_t) (aSig
<< 1)) {
1984 return propagateFloatx80NaNOneArg(a
, status
);
1986 a
= packFloatx80(aSign
, piby2_exp
, pi_sig
);
1987 float_raise(float_flag_inexact
, status
);
1988 return floatx80_move(a
, status
);
1991 if (aExp
== 0 && aSig
== 0) {
1992 return packFloatx80(aSign
, 0, 0);
1995 compact
= floatx80_make_compact(aExp
, aSig
);
1997 user_rnd_mode
= status
->float_rounding_mode
;
1998 user_rnd_prec
= status
->floatx80_rounding_precision
;
1999 status
->float_rounding_mode
= float_round_nearest_even
;
2000 status
->floatx80_rounding_precision
= 80;
2002 if (compact
< 0x3FFB8000 || compact
> 0x4002FFFF) {
2003 /* |X| >= 16 or |X| < 1/16 */
2004 if (compact
> 0x3FFF8000) { /* |X| >= 16 */
2005 if (compact
> 0x40638000) { /* |X| > 2^(100) */
2006 fp0
= packFloatx80(aSign
, piby2_exp
, pi_sig
);
2007 fp1
= packFloatx80(aSign
, 0x0001, one_sig
);
2009 status
->float_rounding_mode
= user_rnd_mode
;
2010 status
->floatx80_rounding_precision
= user_rnd_prec
;
2012 a
= floatx80_sub(fp0
, fp1
, status
);
2014 float_raise(float_flag_inexact
, status
);
2019 fp1
= packFloatx80(1, one_exp
, one_sig
); /* -1 */
2020 fp1
= floatx80_div(fp1
, fp0
, status
); /* X' = -1/X */
2022 fp0
= floatx80_mul(fp1
, fp1
, status
); /* Y = X'*X' */
2023 fp1
= floatx80_mul(fp0
, fp0
, status
); /* Z = Y*Y */
2024 fp3
= float64_to_floatx80(make_float64(0xBFB70BF398539E6A),
2026 fp2
= float64_to_floatx80(make_float64(0x3FBC7187962D1D7D),
2028 fp3
= floatx80_mul(fp3
, fp1
, status
); /* Z*C5 */
2029 fp2
= floatx80_mul(fp2
, fp1
, status
); /* Z*C4 */
2030 fp3
= floatx80_add(fp3
, float64_to_floatx80(
2031 make_float64(0xBFC24924827107B8), status
),
2032 status
); /* C3+Z*C5 */
2033 fp2
= floatx80_add(fp2
, float64_to_floatx80(
2034 make_float64(0x3FC999999996263E), status
),
2035 status
); /* C2+Z*C4 */
2036 fp1
= floatx80_mul(fp1
, fp3
, status
); /* Z*(C3+Z*C5) */
2037 fp2
= floatx80_mul(fp2
, fp0
, status
); /* Y*(C2+Z*C4) */
2038 fp1
= floatx80_add(fp1
, float64_to_floatx80(
2039 make_float64(0xBFD5555555555536), status
),
2040 status
); /* C1+Z*(C3+Z*C5) */
2041 fp0
= floatx80_mul(fp0
, xsave
, status
); /* X'*Y */
2042 /* [Y*(C2+Z*C4)]+[C1+Z*(C3+Z*C5)] */
2043 fp1
= floatx80_add(fp1
, fp2
, status
);
2044 /* X'*Y*([B1+Z*(B3+Z*B5)]+[Y*(B2+Z*(B4+Z*B6))]) ?? */
2045 fp0
= floatx80_mul(fp0
, fp1
, status
);
2046 fp0
= floatx80_add(fp0
, xsave
, status
);
2047 fp1
= packFloatx80(aSign
, piby2_exp
, pi_sig
);
2049 status
->float_rounding_mode
= user_rnd_mode
;
2050 status
->floatx80_rounding_precision
= user_rnd_prec
;
2052 a
= floatx80_add(fp0
, fp1
, status
);
2054 float_raise(float_flag_inexact
, status
);
2058 } else { /* |X| < 1/16 */
2059 if (compact
< 0x3FD78000) { /* |X| < 2^(-40) */
2060 status
->float_rounding_mode
= user_rnd_mode
;
2061 status
->floatx80_rounding_precision
= user_rnd_prec
;
2063 a
= floatx80_move(a
, status
);
2065 float_raise(float_flag_inexact
, status
);
2071 fp0
= floatx80_mul(fp0
, fp0
, status
); /* Y = X*X */
2072 fp1
= floatx80_mul(fp0
, fp0
, status
); /* Z = Y*Y */
2073 fp2
= float64_to_floatx80(make_float64(0x3FB344447F876989),
2075 fp3
= float64_to_floatx80(make_float64(0xBFB744EE7FAF45DB),
2077 fp2
= floatx80_mul(fp2
, fp1
, status
); /* Z*B6 */
2078 fp3
= floatx80_mul(fp3
, fp1
, status
); /* Z*B5 */
2079 fp2
= floatx80_add(fp2
, float64_to_floatx80(
2080 make_float64(0x3FBC71C646940220), status
),
2081 status
); /* B4+Z*B6 */
2082 fp3
= floatx80_add(fp3
, float64_to_floatx80(
2083 make_float64(0xBFC24924921872F9),
2084 status
), status
); /* B3+Z*B5 */
2085 fp2
= floatx80_mul(fp2
, fp1
, status
); /* Z*(B4+Z*B6) */
2086 fp1
= floatx80_mul(fp1
, fp3
, status
); /* Z*(B3+Z*B5) */
2087 fp2
= floatx80_add(fp2
, float64_to_floatx80(
2088 make_float64(0x3FC9999999998FA9), status
),
2089 status
); /* B2+Z*(B4+Z*B6) */
2090 fp1
= floatx80_add(fp1
, float64_to_floatx80(
2091 make_float64(0xBFD5555555555555), status
),
2092 status
); /* B1+Z*(B3+Z*B5) */
2093 fp2
= floatx80_mul(fp2
, fp0
, status
); /* Y*(B2+Z*(B4+Z*B6)) */
2094 fp0
= floatx80_mul(fp0
, xsave
, status
); /* X*Y */
2095 /* [B1+Z*(B3+Z*B5)]+[Y*(B2+Z*(B4+Z*B6))] */
2096 fp1
= floatx80_add(fp1
, fp2
, status
);
2097 /* X*Y*([B1+Z*(B3+Z*B5)]+[Y*(B2+Z*(B4+Z*B6))]) */
2098 fp0
= floatx80_mul(fp0
, fp1
, status
);
2100 status
->float_rounding_mode
= user_rnd_mode
;
2101 status
->floatx80_rounding_precision
= user_rnd_prec
;
2103 a
= floatx80_add(fp0
, xsave
, status
);
2105 float_raise(float_flag_inexact
, status
);
2111 aSig
&= LIT64(0xF800000000000000);
2112 aSig
|= LIT64(0x0400000000000000);
2113 xsave
= packFloatx80(aSign
, aExp
, aSig
); /* F */
2116 fp2
= packFloatx80(0, one_exp
, one_sig
); /* 1 */
2117 fp1
= floatx80_mul(fp1
, xsave
, status
); /* X*F */
2118 fp0
= floatx80_sub(fp0
, xsave
, status
); /* X-F */
2119 fp1
= floatx80_add(fp1
, fp2
, status
); /* 1 + X*F */
2120 fp0
= floatx80_div(fp0
, fp1
, status
); /* U = (X-F)/(1+X*F) */
2122 tbl_index
= compact
;
2124 tbl_index
&= 0x7FFF0000;
2125 tbl_index
-= 0x3FFB0000;
2127 tbl_index
+= compact
& 0x00007800;
2130 fp3
= atan_tbl
[tbl_index
];
2132 fp3
.high
|= aSign
? 0x8000 : 0; /* ATAN(F) */
2134 fp1
= floatx80_mul(fp0
, fp0
, status
); /* V = U*U */
2135 fp2
= float64_to_floatx80(make_float64(0xBFF6687E314987D8),
2137 fp2
= floatx80_add(fp2
, fp1
, status
); /* A3+V */
2138 fp2
= floatx80_mul(fp2
, fp1
, status
); /* V*(A3+V) */
2139 fp1
= floatx80_mul(fp1
, fp0
, status
); /* U*V */
2140 fp2
= floatx80_add(fp2
, float64_to_floatx80(
2141 make_float64(0x4002AC6934A26DB3), status
),
2142 status
); /* A2+V*(A3+V) */
2143 fp1
= floatx80_mul(fp1
, float64_to_floatx80(
2144 make_float64(0xBFC2476F4E1DA28E), status
),
2145 status
); /* A1+U*V */
2146 fp1
= floatx80_mul(fp1
, fp2
, status
); /* A1*U*V*(A2+V*(A3+V)) */
2147 fp0
= floatx80_add(fp0
, fp1
, status
); /* ATAN(U) */
2149 status
->float_rounding_mode
= user_rnd_mode
;
2150 status
->floatx80_rounding_precision
= user_rnd_prec
;
2152 a
= floatx80_add(fp0
, fp3
, status
); /* ATAN(X) */
2154 float_raise(float_flag_inexact
, status
);
2160 /*----------------------------------------------------------------------------
2162 *----------------------------------------------------------------------------*/
2164 floatx80
floatx80_asin(floatx80 a
, float_status
*status
)
2170 int8_t user_rnd_mode
, user_rnd_prec
;
2173 floatx80 fp0
, fp1
, fp2
, one
;
2175 aSig
= extractFloatx80Frac(a
);
2176 aExp
= extractFloatx80Exp(a
);
2177 aSign
= extractFloatx80Sign(a
);
2179 if (aExp
== 0x7FFF && (uint64_t) (aSig
<< 1)) {
2180 return propagateFloatx80NaNOneArg(a
, status
);
2183 if (aExp
== 0 && aSig
== 0) {
2184 return packFloatx80(aSign
, 0, 0);
2187 compact
= floatx80_make_compact(aExp
, aSig
);
2189 if (compact
>= 0x3FFF8000) { /* |X| >= 1 */
2190 if (aExp
== one_exp
&& aSig
== one_sig
) { /* |X| == 1 */
2191 float_raise(float_flag_inexact
, status
);
2192 a
= packFloatx80(aSign
, piby2_exp
, pi_sig
);
2193 return floatx80_move(a
, status
);
2194 } else { /* |X| > 1 */
2195 float_raise(float_flag_invalid
, status
);
2196 return floatx80_default_nan(status
);
2201 user_rnd_mode
= status
->float_rounding_mode
;
2202 user_rnd_prec
= status
->floatx80_rounding_precision
;
2203 status
->float_rounding_mode
= float_round_nearest_even
;
2204 status
->floatx80_rounding_precision
= 80;
2206 one
= packFloatx80(0, one_exp
, one_sig
);
2209 fp1
= floatx80_sub(one
, fp0
, status
); /* 1 - X */
2210 fp2
= floatx80_add(one
, fp0
, status
); /* 1 + X */
2211 fp1
= floatx80_mul(fp2
, fp1
, status
); /* (1+X)*(1-X) */
2212 fp1
= floatx80_sqrt(fp1
, status
); /* SQRT((1+X)*(1-X)) */
2213 fp0
= floatx80_div(fp0
, fp1
, status
); /* X/SQRT((1+X)*(1-X)) */
2215 status
->float_rounding_mode
= user_rnd_mode
;
2216 status
->floatx80_rounding_precision
= user_rnd_prec
;
2218 a
= floatx80_atan(fp0
, status
); /* ATAN(X/SQRT((1+X)*(1-X))) */
2220 float_raise(float_flag_inexact
, status
);
2225 /*----------------------------------------------------------------------------
2227 *----------------------------------------------------------------------------*/
2229 floatx80
floatx80_acos(floatx80 a
, float_status
*status
)
2235 int8_t user_rnd_mode
, user_rnd_prec
;
2238 floatx80 fp0
, fp1
, one
;
2240 aSig
= extractFloatx80Frac(a
);
2241 aExp
= extractFloatx80Exp(a
);
2242 aSign
= extractFloatx80Sign(a
);
2244 if (aExp
== 0x7FFF && (uint64_t) (aSig
<< 1)) {
2245 return propagateFloatx80NaNOneArg(a
, status
);
2247 if (aExp
== 0 && aSig
== 0) {
2248 float_raise(float_flag_inexact
, status
);
2249 return roundAndPackFloatx80(status
->floatx80_rounding_precision
, 0,
2250 piby2_exp
, pi_sig
, 0, status
);
2253 compact
= floatx80_make_compact(aExp
, aSig
);
2255 if (compact
>= 0x3FFF8000) { /* |X| >= 1 */
2256 if (aExp
== one_exp
&& aSig
== one_sig
) { /* |X| == 1 */
2257 if (aSign
) { /* X == -1 */
2258 a
= packFloatx80(0, pi_exp
, pi_sig
);
2259 float_raise(float_flag_inexact
, status
);
2260 return floatx80_move(a
, status
);
2261 } else { /* X == +1 */
2262 return packFloatx80(0, 0, 0);
2264 } else { /* |X| > 1 */
2265 float_raise(float_flag_invalid
, status
);
2266 return floatx80_default_nan(status
);
2270 user_rnd_mode
= status
->float_rounding_mode
;
2271 user_rnd_prec
= status
->floatx80_rounding_precision
;
2272 status
->float_rounding_mode
= float_round_nearest_even
;
2273 status
->floatx80_rounding_precision
= 80;
2275 one
= packFloatx80(0, one_exp
, one_sig
);
2278 fp1
= floatx80_add(one
, fp0
, status
); /* 1 + X */
2279 fp0
= floatx80_sub(one
, fp0
, status
); /* 1 - X */
2280 fp0
= floatx80_div(fp0
, fp1
, status
); /* (1-X)/(1+X) */
2281 fp0
= floatx80_sqrt(fp0
, status
); /* SQRT((1-X)/(1+X)) */
2282 fp0
= floatx80_atan(fp0
, status
); /* ATAN(SQRT((1-X)/(1+X))) */
2284 status
->float_rounding_mode
= user_rnd_mode
;
2285 status
->floatx80_rounding_precision
= user_rnd_prec
;
2287 a
= floatx80_add(fp0
, fp0
, status
); /* 2 * ATAN(SQRT((1-X)/(1+X))) */
2289 float_raise(float_flag_inexact
, status
);
2294 /*----------------------------------------------------------------------------
2295 | Hyperbolic arc tangent
2296 *----------------------------------------------------------------------------*/
2298 floatx80
floatx80_atanh(floatx80 a
, float_status
*status
)
2304 int8_t user_rnd_mode
, user_rnd_prec
;
2307 floatx80 fp0
, fp1
, fp2
, one
;
2309 aSig
= extractFloatx80Frac(a
);
2310 aExp
= extractFloatx80Exp(a
);
2311 aSign
= extractFloatx80Sign(a
);
2313 if (aExp
== 0x7FFF && (uint64_t) (aSig
<< 1)) {
2314 return propagateFloatx80NaNOneArg(a
, status
);
2317 if (aExp
== 0 && aSig
== 0) {
2318 return packFloatx80(aSign
, 0, 0);
2321 compact
= floatx80_make_compact(aExp
, aSig
);
2323 if (compact
>= 0x3FFF8000) { /* |X| >= 1 */
2324 if (aExp
== one_exp
&& aSig
== one_sig
) { /* |X| == 1 */
2325 float_raise(float_flag_divbyzero
, status
);
2326 return packFloatx80(aSign
, floatx80_infinity
.high
,
2327 floatx80_infinity
.low
);
2328 } else { /* |X| > 1 */
2329 float_raise(float_flag_invalid
, status
);
2330 return floatx80_default_nan(status
);
2334 user_rnd_mode
= status
->float_rounding_mode
;
2335 user_rnd_prec
= status
->floatx80_rounding_precision
;
2336 status
->float_rounding_mode
= float_round_nearest_even
;
2337 status
->floatx80_rounding_precision
= 80;
2339 one
= packFloatx80(0, one_exp
, one_sig
);
2340 fp2
= packFloatx80(aSign
, 0x3FFE, one_sig
); /* SIGN(X) * (1/2) */
2341 fp0
= packFloatx80(0, aExp
, aSig
); /* Y = |X| */
2342 fp1
= packFloatx80(1, aExp
, aSig
); /* -Y */
2343 fp0
= floatx80_add(fp0
, fp0
, status
); /* 2Y */
2344 fp1
= floatx80_add(fp1
, one
, status
); /* 1-Y */
2345 fp0
= floatx80_div(fp0
, fp1
, status
); /* Z = 2Y/(1-Y) */
2346 fp0
= floatx80_lognp1(fp0
, status
); /* LOG1P(Z) */
2348 status
->float_rounding_mode
= user_rnd_mode
;
2349 status
->floatx80_rounding_precision
= user_rnd_prec
;
2351 a
= floatx80_mul(fp0
, fp2
,
2352 status
); /* ATANH(X) = SIGN(X) * (1/2) * LOG1P(Z) */
2354 float_raise(float_flag_inexact
, status
);
2359 /*----------------------------------------------------------------------------
2361 *----------------------------------------------------------------------------*/
2363 floatx80
floatx80_etoxm1(floatx80 a
, float_status
*status
)
2369 int8_t user_rnd_mode
, user_rnd_prec
;
2371 int32_t compact
, n
, j
, m
, m1
;
2372 floatx80 fp0
, fp1
, fp2
, fp3
, l2
, sc
, onebysc
;
2374 aSig
= extractFloatx80Frac(a
);
2375 aExp
= extractFloatx80Exp(a
);
2376 aSign
= extractFloatx80Sign(a
);
2378 if (aExp
== 0x7FFF) {
2379 if ((uint64_t) (aSig
<< 1)) {
2380 return propagateFloatx80NaNOneArg(a
, status
);
2383 return packFloatx80(aSign
, one_exp
, one_sig
);
2385 return packFloatx80(0, floatx80_infinity
.high
,
2386 floatx80_infinity
.low
);
2389 if (aExp
== 0 && aSig
== 0) {
2390 return packFloatx80(aSign
, 0, 0);
2393 user_rnd_mode
= status
->float_rounding_mode
;
2394 user_rnd_prec
= status
->floatx80_rounding_precision
;
2395 status
->float_rounding_mode
= float_round_nearest_even
;
2396 status
->floatx80_rounding_precision
= 80;
2398 if (aExp
>= 0x3FFD) { /* |X| >= 1/4 */
2399 compact
= floatx80_make_compact(aExp
, aSig
);
2401 if (compact
<= 0x4004C215) { /* |X| <= 70 log2 */
2404 fp0
= floatx80_mul(fp0
, float32_to_floatx80(
2405 make_float32(0x42B8AA3B), status
),
2406 status
); /* 64/log2 * X */
2407 n
= floatx80_to_int32(fp0
, status
); /* int(64/log2*X) */
2408 fp0
= int32_to_floatx80(n
, status
);
2410 j
= n
& 0x3F; /* J = N mod 64 */
2411 m
= n
/ 64; /* NOTE: this is really arithmetic right shift by 6 */
2413 /* arithmetic right shift is division and
2414 * round towards minus infinity
2419 /*m += 0x3FFF; // biased exponent of 2^(M) */
2420 /*m1 += 0x3FFF; // biased exponent of -2^(-M) */
2423 fp0
= floatx80_mul(fp0
, float32_to_floatx80(
2424 make_float32(0xBC317218), status
),
2425 status
); /* N * L1, L1 = lead(-log2/64) */
2426 l2
= packFloatx80(0, 0x3FDC, LIT64(0x82E308654361C4C6));
2427 fp2
= floatx80_mul(fp2
, l2
, status
); /* N * L2, L1+L2 = -log2/64 */
2428 fp0
= floatx80_add(fp0
, fp1
, status
); /* X + N*L1 */
2429 fp0
= floatx80_add(fp0
, fp2
, status
); /* R */
2431 fp1
= floatx80_mul(fp0
, fp0
, status
); /* S = R*R */
2432 fp2
= float32_to_floatx80(make_float32(0x3950097B),
2434 fp2
= floatx80_mul(fp2
, fp1
, status
); /* fp2 is S*A6 */
2435 fp3
= floatx80_mul(float32_to_floatx80(make_float32(0x3AB60B6A),
2436 status
), fp1
, status
); /* fp3 is S*A5 */
2437 fp2
= floatx80_add(fp2
, float64_to_floatx80(
2438 make_float64(0x3F81111111174385), status
),
2439 status
); /* fp2 IS A4+S*A6 */
2440 fp3
= floatx80_add(fp3
, float64_to_floatx80(
2441 make_float64(0x3FA5555555554F5A), status
),
2442 status
); /* fp3 is A3+S*A5 */
2443 fp2
= floatx80_mul(fp2
, fp1
, status
); /* fp2 IS S*(A4+S*A6) */
2444 fp3
= floatx80_mul(fp3
, fp1
, status
); /* fp3 IS S*(A3+S*A5) */
2445 fp2
= floatx80_add(fp2
, float64_to_floatx80(
2446 make_float64(0x3FC5555555555555), status
),
2447 status
); /* fp2 IS A2+S*(A4+S*A6) */
2448 fp3
= floatx80_add(fp3
, float32_to_floatx80(
2449 make_float32(0x3F000000), status
),
2450 status
); /* fp3 IS A1+S*(A3+S*A5) */
2451 fp2
= floatx80_mul(fp2
, fp1
,
2452 status
); /* fp2 IS S*(A2+S*(A4+S*A6)) */
2453 fp1
= floatx80_mul(fp1
, fp3
,
2454 status
); /* fp1 IS S*(A1+S*(A3+S*A5)) */
2455 fp2
= floatx80_mul(fp2
, fp0
,
2456 status
); /* fp2 IS R*S*(A2+S*(A4+S*A6)) */
2457 fp0
= floatx80_add(fp0
, fp1
,
2458 status
); /* fp0 IS R+S*(A1+S*(A3+S*A5)) */
2459 fp0
= floatx80_add(fp0
, fp2
, status
); /* fp0 IS EXP(R) - 1 */
2461 fp0
= floatx80_mul(fp0
, exp_tbl
[j
],
2462 status
); /* 2^(J/64)*(Exp(R)-1) */
2465 fp1
= float32_to_floatx80(exp_tbl2
[j
], status
);
2466 onebysc
= packFloatx80(1, m1
+ 0x3FFF, one_sig
); /* -2^(-M) */
2467 fp1
= floatx80_add(fp1
, onebysc
, status
);
2468 fp0
= floatx80_add(fp0
, fp1
, status
);
2469 fp0
= floatx80_add(fp0
, exp_tbl
[j
], status
);
2470 } else if (m
< -3) {
2471 fp0
= floatx80_add(fp0
, float32_to_floatx80(exp_tbl2
[j
],
2473 fp0
= floatx80_add(fp0
, exp_tbl
[j
], status
);
2474 onebysc
= packFloatx80(1, m1
+ 0x3FFF, one_sig
); /* -2^(-M) */
2475 fp0
= floatx80_add(fp0
, onebysc
, status
);
2476 } else { /* -3 <= m <= 63 */
2478 fp0
= floatx80_add(fp0
, float32_to_floatx80(exp_tbl2
[j
],
2480 onebysc
= packFloatx80(1, m1
+ 0x3FFF, one_sig
); /* -2^(-M) */
2481 fp1
= floatx80_add(fp1
, onebysc
, status
);
2482 fp0
= floatx80_add(fp0
, fp1
, status
);
2485 sc
= packFloatx80(0, m
+ 0x3FFF, one_sig
);
2487 status
->float_rounding_mode
= user_rnd_mode
;
2488 status
->floatx80_rounding_precision
= user_rnd_prec
;
2490 a
= floatx80_mul(fp0
, sc
, status
);
2492 float_raise(float_flag_inexact
, status
);
2495 } else { /* |X| > 70 log2 */
2497 fp0
= float32_to_floatx80(make_float32(0xBF800000),
2500 status
->float_rounding_mode
= user_rnd_mode
;
2501 status
->floatx80_rounding_precision
= user_rnd_prec
;
2503 a
= floatx80_add(fp0
, float32_to_floatx80(
2504 make_float32(0x00800000), status
),
2505 status
); /* -1 + 2^(-126) */
2507 float_raise(float_flag_inexact
, status
);
2511 status
->float_rounding_mode
= user_rnd_mode
;
2512 status
->floatx80_rounding_precision
= user_rnd_prec
;
2514 return floatx80_etox(a
, status
);
2517 } else { /* |X| < 1/4 */
2518 if (aExp
>= 0x3FBE) {
2520 fp0
= floatx80_mul(fp0
, fp0
, status
); /* S = X*X */
2521 fp1
= float32_to_floatx80(make_float32(0x2F30CAA8),
2523 fp1
= floatx80_mul(fp1
, fp0
, status
); /* S * B12 */
2524 fp2
= float32_to_floatx80(make_float32(0x310F8290),
2526 fp1
= floatx80_add(fp1
, float32_to_floatx80(
2527 make_float32(0x32D73220), status
),
2529 fp2
= floatx80_mul(fp2
, fp0
, status
);
2530 fp1
= floatx80_mul(fp1
, fp0
, status
);
2531 fp2
= floatx80_add(fp2
, float32_to_floatx80(
2532 make_float32(0x3493F281), status
),
2534 fp1
= floatx80_add(fp1
, float64_to_floatx80(
2535 make_float64(0x3EC71DE3A5774682), status
),
2537 fp2
= floatx80_mul(fp2
, fp0
, status
);
2538 fp1
= floatx80_mul(fp1
, fp0
, status
);
2539 fp2
= floatx80_add(fp2
, float64_to_floatx80(
2540 make_float64(0x3EFA01A019D7CB68), status
),
2542 fp1
= floatx80_add(fp1
, float64_to_floatx80(
2543 make_float64(0x3F2A01A01A019DF3), status
),
2545 fp2
= floatx80_mul(fp2
, fp0
, status
);
2546 fp1
= floatx80_mul(fp1
, fp0
, status
);
2547 fp2
= floatx80_add(fp2
, float64_to_floatx80(
2548 make_float64(0x3F56C16C16C170E2), status
),
2550 fp1
= floatx80_add(fp1
, float64_to_floatx80(
2551 make_float64(0x3F81111111111111), status
),
2553 fp2
= floatx80_mul(fp2
, fp0
, status
);
2554 fp1
= floatx80_mul(fp1
, fp0
, status
);
2555 fp2
= floatx80_add(fp2
, float64_to_floatx80(
2556 make_float64(0x3FA5555555555555), status
),
2558 fp3
= packFloatx80(0, 0x3FFC, LIT64(0xAAAAAAAAAAAAAAAB));
2559 fp1
= floatx80_add(fp1
, fp3
, status
); /* B2 */
2560 fp2
= floatx80_mul(fp2
, fp0
, status
);
2561 fp1
= floatx80_mul(fp1
, fp0
, status
);
2563 fp2
= floatx80_mul(fp2
, fp0
, status
);
2564 fp1
= floatx80_mul(fp1
, a
, status
);
2566 fp0
= floatx80_mul(fp0
, float32_to_floatx80(
2567 make_float32(0x3F000000), status
),
2569 fp1
= floatx80_add(fp1
, fp2
, status
); /* Q */
2570 fp0
= floatx80_add(fp0
, fp1
, status
); /* S*B1+Q */
2572 status
->float_rounding_mode
= user_rnd_mode
;
2573 status
->floatx80_rounding_precision
= user_rnd_prec
;
2575 a
= floatx80_add(fp0
, a
, status
);
2577 float_raise(float_flag_inexact
, status
);
2580 } else { /* |X| < 2^(-65) */
2581 sc
= packFloatx80(1, 1, one_sig
);
2584 if (aExp
< 0x0033) { /* |X| < 2^(-16382) */
2585 fp0
= floatx80_mul(fp0
, float64_to_floatx80(
2586 make_float64(0x48B0000000000000), status
),
2588 fp0
= floatx80_add(fp0
, sc
, status
);
2590 status
->float_rounding_mode
= user_rnd_mode
;
2591 status
->floatx80_rounding_precision
= user_rnd_prec
;
2593 a
= floatx80_mul(fp0
, float64_to_floatx80(
2594 make_float64(0x3730000000000000), status
),
2597 status
->float_rounding_mode
= user_rnd_mode
;
2598 status
->floatx80_rounding_precision
= user_rnd_prec
;
2600 a
= floatx80_add(fp0
, sc
, status
);
2603 float_raise(float_flag_inexact
, status
);
2610 /*----------------------------------------------------------------------------
2611 | Hyperbolic tangent
2612 *----------------------------------------------------------------------------*/
2614 floatx80
floatx80_tanh(floatx80 a
, float_status
*status
)
2618 uint64_t aSig
, vSig
;
2620 int8_t user_rnd_mode
, user_rnd_prec
;
2626 aSig
= extractFloatx80Frac(a
);
2627 aExp
= extractFloatx80Exp(a
);
2628 aSign
= extractFloatx80Sign(a
);
2630 if (aExp
== 0x7FFF) {
2631 if ((uint64_t) (aSig
<< 1)) {
2632 return propagateFloatx80NaNOneArg(a
, status
);
2634 return packFloatx80(aSign
, one_exp
, one_sig
);
2637 if (aExp
== 0 && aSig
== 0) {
2638 return packFloatx80(aSign
, 0, 0);
2641 user_rnd_mode
= status
->float_rounding_mode
;
2642 user_rnd_prec
= status
->floatx80_rounding_precision
;
2643 status
->float_rounding_mode
= float_round_nearest_even
;
2644 status
->floatx80_rounding_precision
= 80;
2646 compact
= floatx80_make_compact(aExp
, aSig
);
2648 if (compact
< 0x3FD78000 || compact
> 0x3FFFDDCE) {
2650 if (compact
< 0x3FFF8000) {
2652 status
->float_rounding_mode
= user_rnd_mode
;
2653 status
->floatx80_rounding_precision
= user_rnd_prec
;
2655 a
= floatx80_move(a
, status
);
2657 float_raise(float_flag_inexact
, status
);
2661 if (compact
> 0x40048AA1) {
2664 sign
|= aSign
? 0x80000000 : 0x00000000;
2665 fp0
= float32_to_floatx80(make_float32(sign
), status
);
2667 sign
^= 0x80800000; /* -SIGN(X)*EPS */
2669 status
->float_rounding_mode
= user_rnd_mode
;
2670 status
->floatx80_rounding_precision
= user_rnd_prec
;
2672 a
= floatx80_add(fp0
, float32_to_floatx80(make_float32(sign
),
2675 float_raise(float_flag_inexact
, status
);
2679 fp0
= packFloatx80(0, aExp
+ 1, aSig
); /* Y = 2|X| */
2680 fp0
= floatx80_etox(fp0
, status
); /* FP0 IS EXP(Y) */
2681 fp0
= floatx80_add(fp0
, float32_to_floatx80(
2682 make_float32(0x3F800000),
2683 status
), status
); /* EXP(Y)+1 */
2684 sign
= aSign
? 0x80000000 : 0x00000000;
2685 fp1
= floatx80_div(float32_to_floatx80(make_float32(
2686 sign
^ 0xC0000000), status
), fp0
,
2687 status
); /* -SIGN(X)*2 / [EXP(Y)+1] */
2688 fp0
= float32_to_floatx80(make_float32(sign
| 0x3F800000),
2691 status
->float_rounding_mode
= user_rnd_mode
;
2692 status
->floatx80_rounding_precision
= user_rnd_prec
;
2694 a
= floatx80_add(fp1
, fp0
, status
);
2696 float_raise(float_flag_inexact
, status
);
2701 } else { /* 2**(-40) < |X| < (5/2)LOG2 */
2702 fp0
= packFloatx80(0, aExp
+ 1, aSig
); /* Y = 2|X| */
2703 fp0
= floatx80_etoxm1(fp0
, status
); /* FP0 IS Z = EXPM1(Y) */
2704 fp1
= floatx80_add(fp0
, float32_to_floatx80(make_float32(0x40000000),
2708 vSign
= extractFloatx80Sign(fp1
);
2709 vExp
= extractFloatx80Exp(fp1
);
2710 vSig
= extractFloatx80Frac(fp1
);
2712 fp1
= packFloatx80(vSign
^ aSign
, vExp
, vSig
);
2714 status
->float_rounding_mode
= user_rnd_mode
;
2715 status
->floatx80_rounding_precision
= user_rnd_prec
;
2717 a
= floatx80_div(fp0
, fp1
, status
);
2719 float_raise(float_flag_inexact
, status
);
2725 /*----------------------------------------------------------------------------
2727 *----------------------------------------------------------------------------*/
2729 floatx80
floatx80_sinh(floatx80 a
, float_status
*status
)
2735 int8_t user_rnd_mode
, user_rnd_prec
;
2738 floatx80 fp0
, fp1
, fp2
;
2741 aSig
= extractFloatx80Frac(a
);
2742 aExp
= extractFloatx80Exp(a
);
2743 aSign
= extractFloatx80Sign(a
);
2745 if (aExp
== 0x7FFF) {
2746 if ((uint64_t) (aSig
<< 1)) {
2747 return propagateFloatx80NaNOneArg(a
, status
);
2749 return packFloatx80(aSign
, floatx80_infinity
.high
,
2750 floatx80_infinity
.low
);
2753 if (aExp
== 0 && aSig
== 0) {
2754 return packFloatx80(aSign
, 0, 0);
2757 user_rnd_mode
= status
->float_rounding_mode
;
2758 user_rnd_prec
= status
->floatx80_rounding_precision
;
2759 status
->float_rounding_mode
= float_round_nearest_even
;
2760 status
->floatx80_rounding_precision
= 80;
2762 compact
= floatx80_make_compact(aExp
, aSig
);
2764 if (compact
> 0x400CB167) {
2766 if (compact
> 0x400CB2B3) {
2767 status
->float_rounding_mode
= user_rnd_mode
;
2768 status
->floatx80_rounding_precision
= user_rnd_prec
;
2770 return roundAndPackFloatx80(status
->floatx80_rounding_precision
,
2771 aSign
, 0x8000, aSig
, 0, status
);
2773 fp0
= floatx80_abs(a
); /* Y = |X| */
2774 fp0
= floatx80_sub(fp0
, float64_to_floatx80(
2775 make_float64(0x40C62D38D3D64634), status
),
2776 status
); /* (|X|-16381LOG2_LEAD) */
2777 fp0
= floatx80_sub(fp0
, float64_to_floatx80(
2778 make_float64(0x3D6F90AEB1E75CC7), status
),
2779 status
); /* |X| - 16381 LOG2, ACCURATE */
2780 fp0
= floatx80_etox(fp0
, status
);
2781 fp2
= packFloatx80(aSign
, 0x7FFB, one_sig
);
2783 status
->float_rounding_mode
= user_rnd_mode
;
2784 status
->floatx80_rounding_precision
= user_rnd_prec
;
2786 a
= floatx80_mul(fp0
, fp2
, status
);
2788 float_raise(float_flag_inexact
, status
);
2792 } else { /* |X| < 16380 LOG2 */
2793 fp0
= floatx80_abs(a
); /* Y = |X| */
2794 fp0
= floatx80_etoxm1(fp0
, status
); /* FP0 IS Z = EXPM1(Y) */
2795 fp1
= floatx80_add(fp0
, float32_to_floatx80(make_float32(0x3F800000),
2796 status
), status
); /* 1+Z */
2798 fp0
= floatx80_div(fp0
, fp1
, status
); /* Z/(1+Z) */
2799 fp0
= floatx80_add(fp0
, fp2
, status
);
2801 fact
= packFloat32(aSign
, 0x7E, 0);
2803 status
->float_rounding_mode
= user_rnd_mode
;
2804 status
->floatx80_rounding_precision
= user_rnd_prec
;
2806 a
= floatx80_mul(fp0
, float32_to_floatx80(fact
, status
), status
);
2808 float_raise(float_flag_inexact
, status
);
2814 /*----------------------------------------------------------------------------
2816 *----------------------------------------------------------------------------*/
2818 floatx80
floatx80_cosh(floatx80 a
, float_status
*status
)
2823 int8_t user_rnd_mode
, user_rnd_prec
;
2828 aSig
= extractFloatx80Frac(a
);
2829 aExp
= extractFloatx80Exp(a
);
2831 if (aExp
== 0x7FFF) {
2832 if ((uint64_t) (aSig
<< 1)) {
2833 return propagateFloatx80NaNOneArg(a
, status
);
2835 return packFloatx80(0, floatx80_infinity
.high
,
2836 floatx80_infinity
.low
);
2839 if (aExp
== 0 && aSig
== 0) {
2840 return packFloatx80(0, one_exp
, one_sig
);
2843 user_rnd_mode
= status
->float_rounding_mode
;
2844 user_rnd_prec
= status
->floatx80_rounding_precision
;
2845 status
->float_rounding_mode
= float_round_nearest_even
;
2846 status
->floatx80_rounding_precision
= 80;
2848 compact
= floatx80_make_compact(aExp
, aSig
);
2850 if (compact
> 0x400CB167) {
2851 if (compact
> 0x400CB2B3) {
2852 status
->float_rounding_mode
= user_rnd_mode
;
2853 status
->floatx80_rounding_precision
= user_rnd_prec
;
2854 return roundAndPackFloatx80(status
->floatx80_rounding_precision
, 0,
2855 0x8000, one_sig
, 0, status
);
2857 fp0
= packFloatx80(0, aExp
, aSig
);
2858 fp0
= floatx80_sub(fp0
, float64_to_floatx80(
2859 make_float64(0x40C62D38D3D64634), status
),
2861 fp0
= floatx80_sub(fp0
, float64_to_floatx80(
2862 make_float64(0x3D6F90AEB1E75CC7), status
),
2864 fp0
= floatx80_etox(fp0
, status
);
2865 fp1
= packFloatx80(0, 0x7FFB, one_sig
);
2867 status
->float_rounding_mode
= user_rnd_mode
;
2868 status
->floatx80_rounding_precision
= user_rnd_prec
;
2870 a
= floatx80_mul(fp0
, fp1
, status
);
2872 float_raise(float_flag_inexact
, status
);
2878 fp0
= packFloatx80(0, aExp
, aSig
); /* |X| */
2879 fp0
= floatx80_etox(fp0
, status
); /* EXP(|X|) */
2880 fp0
= floatx80_mul(fp0
, float32_to_floatx80(make_float32(0x3F000000),
2881 status
), status
); /* (1/2)*EXP(|X|) */
2882 fp1
= float32_to_floatx80(make_float32(0x3E800000), status
); /* 1/4 */
2883 fp1
= floatx80_div(fp1
, fp0
, status
); /* 1/(2*EXP(|X|)) */
2885 status
->float_rounding_mode
= user_rnd_mode
;
2886 status
->floatx80_rounding_precision
= user_rnd_prec
;
2888 a
= floatx80_add(fp0
, fp1
, status
);
2890 float_raise(float_flag_inexact
, status
);