2 * Ported from a work by Andreas Grabher for Previous, NeXT Computer Emulator,
3 * derived from NetBSD M68040 FPSP functions,
4 * derived from release 2a of the SoftFloat IEC/IEEE Floating-point Arithmetic
5 * Package. Those parts of the code (and some later contributions) are
6 * provided under that license, as detailed below.
7 * It has subsequently been modified by contributors to the QEMU Project,
8 * so some portions are provided under:
9 * the SoftFloat-2a license
13 * Any future contributions to this file will be taken to be licensed under
14 * the Softfloat-2a license unless specifically indicated otherwise.
17 /* Portions of this work are licensed under the terms of the GNU GPL,
18 * version 2 or later. See the COPYING file in the top-level directory.
21 #include "qemu/osdep.h"
22 #include "softfloat.h"
23 #include "fpu/softfloat-macros.h"
24 #include "softfloat_fpsp_tables.h"
27 #define piby2_exp 0x3FFF
28 #define pi_sig LIT64(0xc90fdaa22168c235)
30 static floatx80
propagateFloatx80NaNOneArg(floatx80 a
, float_status
*status
)
32 if (floatx80_is_signaling_nan(a
, status
)) {
33 float_raise(float_flag_invalid
, status
);
36 if (status
->default_nan_mode
) {
37 return floatx80_default_nan(status
);
40 return floatx80_maybe_silence_nan(a
, status
);
43 /*----------------------------------------------------------------------------
44 | Returns the modulo remainder of the extended double-precision floating-point
45 | value `a' with respect to the corresponding value `b'.
46 *----------------------------------------------------------------------------*/
48 floatx80
floatx80_mod(floatx80 a
, floatx80 b
, float_status
*status
)
51 int32_t aExp
, bExp
, expDiff
;
52 uint64_t aSig0
, aSig1
, bSig
;
53 uint64_t qTemp
, term0
, term1
;
55 aSig0
= extractFloatx80Frac(a
);
56 aExp
= extractFloatx80Exp(a
);
57 aSign
= extractFloatx80Sign(a
);
58 bSig
= extractFloatx80Frac(b
);
59 bExp
= extractFloatx80Exp(b
);
62 if ((uint64_t) (aSig0
<< 1)
63 || ((bExp
== 0x7FFF) && (uint64_t) (bSig
<< 1))) {
64 return propagateFloatx80NaN(a
, b
, status
);
69 if ((uint64_t) (bSig
<< 1)) {
70 return propagateFloatx80NaN(a
, b
, status
);
77 float_raise(float_flag_invalid
, status
);
78 return floatx80_default_nan(status
);
80 normalizeFloatx80Subnormal(bSig
, &bExp
, &bSig
);
83 if ((uint64_t) (aSig0
<< 1) == 0) {
86 normalizeFloatx80Subnormal(aSig0
, &aExp
, &aSig0
);
88 bSig
|= LIT64(0x8000000000000000);
90 expDiff
= aExp
- bExp
;
95 qTemp
= (bSig
<= aSig0
);
100 while (0 < expDiff
) {
101 qTemp
= estimateDiv128To64(aSig0
, aSig1
, bSig
);
102 qTemp
= (2 < qTemp
) ? qTemp
- 2 : 0;
103 mul64To128(bSig
, qTemp
, &term0
, &term1
);
104 sub128(aSig0
, aSig1
, term0
, term1
, &aSig0
, &aSig1
);
105 shortShift128Left(aSig0
, aSig1
, 62, &aSig0
, &aSig1
);
109 qTemp
= estimateDiv128To64(aSig0
, aSig1
, bSig
);
110 qTemp
= (2 < qTemp
) ? qTemp
- 2 : 0;
111 qTemp
>>= 64 - expDiff
;
112 mul64To128(bSig
, qTemp
<< (64 - expDiff
), &term0
, &term1
);
113 sub128(aSig0
, aSig1
, term0
, term1
, &aSig0
, &aSig1
);
114 shortShift128Left(0, bSig
, 64 - expDiff
, &term0
, &term1
);
115 while (le128(term0
, term1
, aSig0
, aSig1
)) {
117 sub128(aSig0
, aSig1
, term0
, term1
, &aSig0
, &aSig1
);
121 normalizeRoundAndPackFloatx80(
122 80, zSign
, bExp
+ expDiff
, aSig0
, aSig1
, status
);
125 /*----------------------------------------------------------------------------
126 | Returns the mantissa of the extended double-precision floating-point
128 *----------------------------------------------------------------------------*/
130 floatx80
floatx80_getman(floatx80 a
, float_status
*status
)
136 aSig
= extractFloatx80Frac(a
);
137 aExp
= extractFloatx80Exp(a
);
138 aSign
= extractFloatx80Sign(a
);
140 if (aExp
== 0x7FFF) {
141 if ((uint64_t) (aSig
<< 1)) {
142 return propagateFloatx80NaNOneArg(a
, status
);
144 float_raise(float_flag_invalid
, status
);
145 return floatx80_default_nan(status
);
150 return packFloatx80(aSign
, 0, 0);
152 normalizeFloatx80Subnormal(aSig
, &aExp
, &aSig
);
155 return roundAndPackFloatx80(status
->floatx80_rounding_precision
, aSign
,
156 0x3FFF, aSig
, 0, status
);
159 /*----------------------------------------------------------------------------
160 | Returns the exponent of the extended double-precision floating-point
161 | value `a' as an extended double-precision value.
162 *----------------------------------------------------------------------------*/
164 floatx80
floatx80_getexp(floatx80 a
, float_status
*status
)
170 aSig
= extractFloatx80Frac(a
);
171 aExp
= extractFloatx80Exp(a
);
172 aSign
= extractFloatx80Sign(a
);
174 if (aExp
== 0x7FFF) {
175 if ((uint64_t) (aSig
<< 1)) {
176 return propagateFloatx80NaNOneArg(a
, status
);
178 float_raise(float_flag_invalid
, status
);
179 return floatx80_default_nan(status
);
184 return packFloatx80(aSign
, 0, 0);
186 normalizeFloatx80Subnormal(aSig
, &aExp
, &aSig
);
189 return int32_to_floatx80(aExp
- 0x3FFF, status
);
192 /*----------------------------------------------------------------------------
193 | Scales extended double-precision floating-point value in operand `a' by
194 | value `b'. The function truncates the value in the second operand 'b' to
195 | an integral value and adds that value to the exponent of the operand 'a'.
196 | The operation performed according to the IEC/IEEE Standard for Binary
197 | Floating-Point Arithmetic.
198 *----------------------------------------------------------------------------*/
200 floatx80
floatx80_scale(floatx80 a
, floatx80 b
, float_status
*status
)
203 int32_t aExp
, bExp
, shiftCount
;
206 aSig
= extractFloatx80Frac(a
);
207 aExp
= extractFloatx80Exp(a
);
208 aSign
= extractFloatx80Sign(a
);
209 bSig
= extractFloatx80Frac(b
);
210 bExp
= extractFloatx80Exp(b
);
211 bSign
= extractFloatx80Sign(b
);
213 if (bExp
== 0x7FFF) {
214 if ((uint64_t) (bSig
<< 1) ||
215 ((aExp
== 0x7FFF) && (uint64_t) (aSig
<< 1))) {
216 return propagateFloatx80NaN(a
, b
, status
);
218 float_raise(float_flag_invalid
, status
);
219 return floatx80_default_nan(status
);
221 if (aExp
== 0x7FFF) {
222 if ((uint64_t) (aSig
<< 1)) {
223 return propagateFloatx80NaN(a
, b
, status
);
225 return packFloatx80(aSign
, floatx80_infinity
.high
,
226 floatx80_infinity
.low
);
230 return packFloatx80(aSign
, 0, 0);
235 normalizeFloatx80Subnormal(aSig
, &aExp
, &aSig
);
243 aExp
= bSign
? -0x6001 : 0xE000;
244 return roundAndPackFloatx80(status
->floatx80_rounding_precision
,
245 aSign
, aExp
, aSig
, 0, status
);
248 shiftCount
= 0x403E - bExp
;
250 aExp
= bSign
? (aExp
- bSig
) : (aExp
+ bSig
);
252 return roundAndPackFloatx80(status
->floatx80_rounding_precision
,
253 aSign
, aExp
, aSig
, 0, status
);
256 floatx80
floatx80_move(floatx80 a
, float_status
*status
)
262 aSig
= extractFloatx80Frac(a
);
263 aExp
= extractFloatx80Exp(a
);
264 aSign
= extractFloatx80Sign(a
);
266 if (aExp
== 0x7FFF) {
267 if ((uint64_t)(aSig
<< 1)) {
268 return propagateFloatx80NaNOneArg(a
, status
);
276 normalizeRoundAndPackFloatx80(status
->floatx80_rounding_precision
,
277 aSign
, aExp
, aSig
, 0, status
);
279 return roundAndPackFloatx80(status
->floatx80_rounding_precision
, aSign
,
280 aExp
, aSig
, 0, status
);
283 /*----------------------------------------------------------------------------
284 | Algorithms for transcendental functions supported by MC68881 and MC68882
285 | mathematical coprocessors. The functions are derived from FPSP library.
286 *----------------------------------------------------------------------------*/
288 #define one_exp 0x3FFF
289 #define one_sig LIT64(0x8000000000000000)
291 /*----------------------------------------------------------------------------
292 | Function for compactifying extended double-precision floating point values.
293 *----------------------------------------------------------------------------*/
295 static int32_t floatx80_make_compact(int32_t aExp
, uint64_t aSig
)
297 return (aExp
<< 16) | (aSig
>> 48);
300 /*----------------------------------------------------------------------------
301 | Log base e of x plus 1
302 *----------------------------------------------------------------------------*/
304 floatx80
floatx80_lognp1(floatx80 a
, float_status
*status
)
310 int8_t user_rnd_mode
, user_rnd_prec
;
312 int32_t compact
, j
, k
;
313 floatx80 fp0
, fp1
, fp2
, fp3
, f
, logof2
, klog2
, saveu
;
315 aSig
= extractFloatx80Frac(a
);
316 aExp
= extractFloatx80Exp(a
);
317 aSign
= extractFloatx80Sign(a
);
319 if (aExp
== 0x7FFF) {
320 if ((uint64_t) (aSig
<< 1)) {
321 propagateFloatx80NaNOneArg(a
, status
);
324 float_raise(float_flag_invalid
, status
);
325 return floatx80_default_nan(status
);
327 return packFloatx80(0, floatx80_infinity
.high
, floatx80_infinity
.low
);
330 if (aExp
== 0 && aSig
== 0) {
331 return packFloatx80(aSign
, 0, 0);
334 if (aSign
&& aExp
>= one_exp
) {
335 if (aExp
== one_exp
&& aSig
== one_sig
) {
336 float_raise(float_flag_divbyzero
, status
);
337 packFloatx80(aSign
, floatx80_infinity
.high
, floatx80_infinity
.low
);
339 float_raise(float_flag_invalid
, status
);
340 return floatx80_default_nan(status
);
343 if (aExp
< 0x3f99 || (aExp
== 0x3f99 && aSig
== one_sig
)) {
344 /* <= min threshold */
345 float_raise(float_flag_inexact
, status
);
346 return floatx80_move(a
, status
);
349 user_rnd_mode
= status
->float_rounding_mode
;
350 user_rnd_prec
= status
->floatx80_rounding_precision
;
351 status
->float_rounding_mode
= float_round_nearest_even
;
352 status
->floatx80_rounding_precision
= 80;
354 compact
= floatx80_make_compact(aExp
, aSig
);
359 fp0
= floatx80_add(fp0
, float32_to_floatx80(make_float32(0x3F800000),
360 status
), status
); /* X = (1+Z) */
362 aExp
= extractFloatx80Exp(fp0
);
363 aSig
= extractFloatx80Frac(fp0
);
365 compact
= floatx80_make_compact(aExp
, aSig
);
367 if (compact
< 0x3FFE8000 || compact
> 0x3FFFC000) {
368 /* |X| < 1/2 or |X| > 3/2 */
370 fp1
= int32_to_floatx80(k
, status
);
372 fSig
= (aSig
& LIT64(0xFE00000000000000)) | LIT64(0x0100000000000000);
373 j
= (fSig
>> 56) & 0x7E; /* DISPLACEMENT FOR 1/F */
375 f
= packFloatx80(0, 0x3FFF, fSig
); /* F */
376 fp0
= packFloatx80(0, 0x3FFF, aSig
); /* Y */
378 fp0
= floatx80_sub(fp0
, f
, status
); /* Y-F */
382 fp0
= floatx80_mul(fp0
, log_tbl
[j
], status
); /* FP0 IS U = (Y-F)/F */
383 logof2
= packFloatx80(0, 0x3FFE, LIT64(0xB17217F7D1CF79AC));
384 klog2
= floatx80_mul(fp1
, logof2
, status
); /* FP1 IS K*LOG2 */
385 fp2
= floatx80_mul(fp0
, fp0
, status
); /* FP2 IS V=U*U */
390 fp1
= floatx80_mul(fp1
, float64_to_floatx80(
391 make_float64(0x3FC2499AB5E4040B), status
),
393 fp2
= floatx80_mul(fp2
, float64_to_floatx80(
394 make_float64(0xBFC555B5848CB7DB), status
),
396 fp1
= floatx80_add(fp1
, float64_to_floatx80(
397 make_float64(0x3FC99999987D8730), status
),
398 status
); /* A4+V*A6 */
399 fp2
= floatx80_add(fp2
, float64_to_floatx80(
400 make_float64(0xBFCFFFFFFF6F7E97), status
),
401 status
); /* A3+V*A5 */
402 fp1
= floatx80_mul(fp1
, fp3
, status
); /* V*(A4+V*A6) */
403 fp2
= floatx80_mul(fp2
, fp3
, status
); /* V*(A3+V*A5) */
404 fp1
= floatx80_add(fp1
, float64_to_floatx80(
405 make_float64(0x3FD55555555555A4), status
),
406 status
); /* A2+V*(A4+V*A6) */
407 fp2
= floatx80_add(fp2
, float64_to_floatx80(
408 make_float64(0xBFE0000000000008), status
),
409 status
); /* A1+V*(A3+V*A5) */
410 fp1
= floatx80_mul(fp1
, fp3
, status
); /* V*(A2+V*(A4+V*A6)) */
411 fp2
= floatx80_mul(fp2
, fp3
, status
); /* V*(A1+V*(A3+V*A5)) */
412 fp1
= floatx80_mul(fp1
, fp0
, status
); /* U*V*(A2+V*(A4+V*A6)) */
413 fp0
= floatx80_add(fp0
, fp2
, status
); /* U+V*(A1+V*(A3+V*A5)) */
415 fp1
= floatx80_add(fp1
, log_tbl
[j
+ 1],
416 status
); /* LOG(F)+U*V*(A2+V*(A4+V*A6)) */
417 fp0
= floatx80_add(fp0
, fp1
, status
); /* FP0 IS LOG(F) + LOG(1+U) */
419 status
->float_rounding_mode
= user_rnd_mode
;
420 status
->floatx80_rounding_precision
= user_rnd_prec
;
422 a
= floatx80_add(fp0
, klog2
, status
);
424 float_raise(float_flag_inexact
, status
);
427 } else if (compact
< 0x3FFEF07D || compact
> 0x3FFF8841) {
428 /* |X| < 1/16 or |X| > -1/16 */
430 fSig
= (aSig
& LIT64(0xFE00000000000000)) | LIT64(0x0100000000000000);
431 f
= packFloatx80(0, 0x3FFF, fSig
); /* F */
432 j
= (fSig
>> 56) & 0x7E; /* DISPLACEMENT FOR 1/F */
434 if (compact
>= 0x3FFF8000) { /* 1+Z >= 1 */
436 fp0
= floatx80_sub(float32_to_floatx80(make_float32(0x3F800000),
437 status
), f
, status
); /* 1-F */
438 fp0
= floatx80_add(fp0
, fp1
, status
); /* FP0 IS Y-F = (1-F)+Z */
439 fp1
= packFloatx80(0, 0, 0); /* K = 0 */
442 fp0
= floatx80_sub(float32_to_floatx80(make_float32(0x40000000),
443 status
), f
, status
); /* 2-F */
444 fp1
= floatx80_add(fp1
, fp1
, status
); /* 2Z */
445 fp0
= floatx80_add(fp0
, fp1
, status
); /* FP0 IS Y-F = (2-F)+2Z */
446 fp1
= packFloatx80(1, one_exp
, one_sig
); /* K = -1 */
451 fp1
= floatx80_add(fp1
, fp1
, status
); /* FP1 IS 2Z */
452 fp0
= floatx80_add(fp0
, float32_to_floatx80(make_float32(0x3F800000),
453 status
), status
); /* FP0 IS 1+X */
456 fp1
= floatx80_div(fp1
, fp0
, status
); /* U */
458 fp0
= floatx80_mul(fp1
, fp1
, status
); /* FP0 IS V = U*U */
459 fp1
= floatx80_mul(fp0
, fp0
, status
); /* FP1 IS W = V*V */
461 fp3
= float64_to_floatx80(make_float64(0x3F175496ADD7DAD6),
463 fp2
= float64_to_floatx80(make_float64(0x3F3C71C2FE80C7E0),
465 fp3
= floatx80_mul(fp3
, fp1
, status
); /* W*B5 */
466 fp2
= floatx80_mul(fp2
, fp1
, status
); /* W*B4 */
467 fp3
= floatx80_add(fp3
, float64_to_floatx80(
468 make_float64(0x3F624924928BCCFF), status
),
469 status
); /* B3+W*B5 */
470 fp2
= floatx80_add(fp2
, float64_to_floatx80(
471 make_float64(0x3F899999999995EC), status
),
472 status
); /* B2+W*B4 */
473 fp1
= floatx80_mul(fp1
, fp3
, status
); /* W*(B3+W*B5) */
474 fp2
= floatx80_mul(fp2
, fp0
, status
); /* V*(B2+W*B4) */
475 fp1
= floatx80_add(fp1
, float64_to_floatx80(
476 make_float64(0x3FB5555555555555), status
),
477 status
); /* B1+W*(B3+W*B5) */
479 fp0
= floatx80_mul(fp0
, saveu
, status
); /* FP0 IS U*V */
480 fp1
= floatx80_add(fp1
, fp2
,
481 status
); /* B1+W*(B3+W*B5) + V*(B2+W*B4) */
482 fp0
= floatx80_mul(fp0
, fp1
,
483 status
); /* U*V*([B1+W*(B3+W*B5)] + [V*(B2+W*B4)]) */
485 status
->float_rounding_mode
= user_rnd_mode
;
486 status
->floatx80_rounding_precision
= user_rnd_prec
;
488 a
= floatx80_add(fp0
, saveu
, status
);
490 /*if (!floatx80_is_zero(a)) { */
491 float_raise(float_flag_inexact
, status
);
498 /*----------------------------------------------------------------------------
500 *----------------------------------------------------------------------------*/
502 floatx80
floatx80_logn(floatx80 a
, float_status
*status
)
508 int8_t user_rnd_mode
, user_rnd_prec
;
510 int32_t compact
, j
, k
, adjk
;
511 floatx80 fp0
, fp1
, fp2
, fp3
, f
, logof2
, klog2
, saveu
;
513 aSig
= extractFloatx80Frac(a
);
514 aExp
= extractFloatx80Exp(a
);
515 aSign
= extractFloatx80Sign(a
);
517 if (aExp
== 0x7FFF) {
518 if ((uint64_t) (aSig
<< 1)) {
519 propagateFloatx80NaNOneArg(a
, status
);
522 return packFloatx80(0, floatx80_infinity
.high
,
523 floatx80_infinity
.low
);
530 if (aSig
== 0) { /* zero */
531 float_raise(float_flag_divbyzero
, status
);
532 return packFloatx80(1, floatx80_infinity
.high
,
533 floatx80_infinity
.low
);
535 if ((aSig
& one_sig
) == 0) { /* denormal */
536 normalizeFloatx80Subnormal(aSig
, &aExp
, &aSig
);
539 a
= packFloatx80(aSign
, aExp
, aSig
);
544 float_raise(float_flag_invalid
, status
);
545 return floatx80_default_nan(status
);
548 user_rnd_mode
= status
->float_rounding_mode
;
549 user_rnd_prec
= status
->floatx80_rounding_precision
;
550 status
->float_rounding_mode
= float_round_nearest_even
;
551 status
->floatx80_rounding_precision
= 80;
553 compact
= floatx80_make_compact(aExp
, aSig
);
555 if (compact
< 0x3FFEF07D || compact
> 0x3FFF8841) {
556 /* |X| < 15/16 or |X| > 17/16 */
559 fp1
= int32_to_floatx80(k
, status
);
561 fSig
= (aSig
& LIT64(0xFE00000000000000)) | LIT64(0x0100000000000000);
562 j
= (fSig
>> 56) & 0x7E; /* DISPLACEMENT FOR 1/F */
564 f
= packFloatx80(0, 0x3FFF, fSig
); /* F */
565 fp0
= packFloatx80(0, 0x3FFF, aSig
); /* Y */
567 fp0
= floatx80_sub(fp0
, f
, status
); /* Y-F */
570 fp0
= floatx80_mul(fp0
, log_tbl
[j
], status
); /* FP0 IS U = (Y-F)/F */
571 logof2
= packFloatx80(0, 0x3FFE, LIT64(0xB17217F7D1CF79AC));
572 klog2
= floatx80_mul(fp1
, logof2
, status
); /* FP1 IS K*LOG2 */
573 fp2
= floatx80_mul(fp0
, fp0
, status
); /* FP2 IS V=U*U */
578 fp1
= floatx80_mul(fp1
, float64_to_floatx80(
579 make_float64(0x3FC2499AB5E4040B), status
),
581 fp2
= floatx80_mul(fp2
, float64_to_floatx80(
582 make_float64(0xBFC555B5848CB7DB), status
),
584 fp1
= floatx80_add(fp1
, float64_to_floatx80(
585 make_float64(0x3FC99999987D8730), status
),
586 status
); /* A4+V*A6 */
587 fp2
= floatx80_add(fp2
, float64_to_floatx80(
588 make_float64(0xBFCFFFFFFF6F7E97), status
),
589 status
); /* A3+V*A5 */
590 fp1
= floatx80_mul(fp1
, fp3
, status
); /* V*(A4+V*A6) */
591 fp2
= floatx80_mul(fp2
, fp3
, status
); /* V*(A3+V*A5) */
592 fp1
= floatx80_add(fp1
, float64_to_floatx80(
593 make_float64(0x3FD55555555555A4), status
),
594 status
); /* A2+V*(A4+V*A6) */
595 fp2
= floatx80_add(fp2
, float64_to_floatx80(
596 make_float64(0xBFE0000000000008), status
),
597 status
); /* A1+V*(A3+V*A5) */
598 fp1
= floatx80_mul(fp1
, fp3
, status
); /* V*(A2+V*(A4+V*A6)) */
599 fp2
= floatx80_mul(fp2
, fp3
, status
); /* V*(A1+V*(A3+V*A5)) */
600 fp1
= floatx80_mul(fp1
, fp0
, status
); /* U*V*(A2+V*(A4+V*A6)) */
601 fp0
= floatx80_add(fp0
, fp2
, status
); /* U+V*(A1+V*(A3+V*A5)) */
603 fp1
= floatx80_add(fp1
, log_tbl
[j
+ 1],
604 status
); /* LOG(F)+U*V*(A2+V*(A4+V*A6)) */
605 fp0
= floatx80_add(fp0
, fp1
, status
); /* FP0 IS LOG(F) + LOG(1+U) */
607 status
->float_rounding_mode
= user_rnd_mode
;
608 status
->floatx80_rounding_precision
= user_rnd_prec
;
610 a
= floatx80_add(fp0
, klog2
, status
);
612 float_raise(float_flag_inexact
, status
);
615 } else { /* |X-1| >= 1/16 */
618 fp1
= floatx80_sub(fp1
, float32_to_floatx80(make_float32(0x3F800000),
619 status
), status
); /* FP1 IS X-1 */
620 fp0
= floatx80_add(fp0
, float32_to_floatx80(make_float32(0x3F800000),
621 status
), status
); /* FP0 IS X+1 */
622 fp1
= floatx80_add(fp1
, fp1
, status
); /* FP1 IS 2(X-1) */
625 fp1
= floatx80_div(fp1
, fp0
, status
); /* U */
627 fp0
= floatx80_mul(fp1
, fp1
, status
); /* FP0 IS V = U*U */
628 fp1
= floatx80_mul(fp0
, fp0
, status
); /* FP1 IS W = V*V */
630 fp3
= float64_to_floatx80(make_float64(0x3F175496ADD7DAD6),
632 fp2
= float64_to_floatx80(make_float64(0x3F3C71C2FE80C7E0),
634 fp3
= floatx80_mul(fp3
, fp1
, status
); /* W*B5 */
635 fp2
= floatx80_mul(fp2
, fp1
, status
); /* W*B4 */
636 fp3
= floatx80_add(fp3
, float64_to_floatx80(
637 make_float64(0x3F624924928BCCFF), status
),
638 status
); /* B3+W*B5 */
639 fp2
= floatx80_add(fp2
, float64_to_floatx80(
640 make_float64(0x3F899999999995EC), status
),
641 status
); /* B2+W*B4 */
642 fp1
= floatx80_mul(fp1
, fp3
, status
); /* W*(B3+W*B5) */
643 fp2
= floatx80_mul(fp2
, fp0
, status
); /* V*(B2+W*B4) */
644 fp1
= floatx80_add(fp1
, float64_to_floatx80(
645 make_float64(0x3FB5555555555555), status
),
646 status
); /* B1+W*(B3+W*B5) */
648 fp0
= floatx80_mul(fp0
, saveu
, status
); /* FP0 IS U*V */
649 fp1
= floatx80_add(fp1
, fp2
, status
); /* B1+W*(B3+W*B5) + V*(B2+W*B4) */
650 fp0
= floatx80_mul(fp0
, fp1
,
651 status
); /* U*V*([B1+W*(B3+W*B5)] + [V*(B2+W*B4)]) */
653 status
->float_rounding_mode
= user_rnd_mode
;
654 status
->floatx80_rounding_precision
= user_rnd_prec
;
656 a
= floatx80_add(fp0
, saveu
, status
);
658 /*if (!floatx80_is_zero(a)) { */
659 float_raise(float_flag_inexact
, status
);
666 /*----------------------------------------------------------------------------
668 *----------------------------------------------------------------------------*/
670 floatx80
floatx80_log10(floatx80 a
, float_status
*status
)
676 int8_t user_rnd_mode
, user_rnd_prec
;
680 aSig
= extractFloatx80Frac(a
);
681 aExp
= extractFloatx80Exp(a
);
682 aSign
= extractFloatx80Sign(a
);
684 if (aExp
== 0x7FFF) {
685 if ((uint64_t) (aSig
<< 1)) {
686 propagateFloatx80NaNOneArg(a
, status
);
689 return packFloatx80(0, floatx80_infinity
.high
,
690 floatx80_infinity
.low
);
694 if (aExp
== 0 && aSig
== 0) {
695 float_raise(float_flag_divbyzero
, status
);
696 return packFloatx80(1, floatx80_infinity
.high
,
697 floatx80_infinity
.low
);
701 float_raise(float_flag_invalid
, status
);
702 return floatx80_default_nan(status
);
705 user_rnd_mode
= status
->float_rounding_mode
;
706 user_rnd_prec
= status
->floatx80_rounding_precision
;
707 status
->float_rounding_mode
= float_round_nearest_even
;
708 status
->floatx80_rounding_precision
= 80;
710 fp0
= floatx80_logn(a
, status
);
711 fp1
= packFloatx80(0, 0x3FFD, LIT64(0xDE5BD8A937287195)); /* INV_L10 */
713 status
->float_rounding_mode
= user_rnd_mode
;
714 status
->floatx80_rounding_precision
= user_rnd_prec
;
716 a
= floatx80_mul(fp0
, fp1
, status
); /* LOGN(X)*INV_L10 */
718 float_raise(float_flag_inexact
, status
);
723 /*----------------------------------------------------------------------------
725 *----------------------------------------------------------------------------*/
727 floatx80
floatx80_log2(floatx80 a
, float_status
*status
)
733 int8_t user_rnd_mode
, user_rnd_prec
;
737 aSig
= extractFloatx80Frac(a
);
738 aExp
= extractFloatx80Exp(a
);
739 aSign
= extractFloatx80Sign(a
);
741 if (aExp
== 0x7FFF) {
742 if ((uint64_t) (aSig
<< 1)) {
743 propagateFloatx80NaNOneArg(a
, status
);
746 return packFloatx80(0, floatx80_infinity
.high
,
747 floatx80_infinity
.low
);
753 float_raise(float_flag_divbyzero
, status
);
754 return packFloatx80(1, floatx80_infinity
.high
,
755 floatx80_infinity
.low
);
757 normalizeFloatx80Subnormal(aSig
, &aExp
, &aSig
);
761 float_raise(float_flag_invalid
, status
);
762 return floatx80_default_nan(status
);
765 user_rnd_mode
= status
->float_rounding_mode
;
766 user_rnd_prec
= status
->floatx80_rounding_precision
;
767 status
->float_rounding_mode
= float_round_nearest_even
;
768 status
->floatx80_rounding_precision
= 80;
770 if (aSig
== one_sig
) { /* X is 2^k */
771 status
->float_rounding_mode
= user_rnd_mode
;
772 status
->floatx80_rounding_precision
= user_rnd_prec
;
774 a
= int32_to_floatx80(aExp
- 0x3FFF, status
);
776 fp0
= floatx80_logn(a
, status
);
777 fp1
= packFloatx80(0, 0x3FFF, LIT64(0xB8AA3B295C17F0BC)); /* INV_L2 */
779 status
->float_rounding_mode
= user_rnd_mode
;
780 status
->floatx80_rounding_precision
= user_rnd_prec
;
782 a
= floatx80_mul(fp0
, fp1
, status
); /* LOGN(X)*INV_L2 */
785 float_raise(float_flag_inexact
, status
);
790 /*----------------------------------------------------------------------------
792 *----------------------------------------------------------------------------*/
794 floatx80
floatx80_etox(floatx80 a
, float_status
*status
)
800 int8_t user_rnd_mode
, user_rnd_prec
;
802 int32_t compact
, n
, j
, k
, m
, m1
;
803 floatx80 fp0
, fp1
, fp2
, fp3
, l2
, scale
, adjscale
;
806 aSig
= extractFloatx80Frac(a
);
807 aExp
= extractFloatx80Exp(a
);
808 aSign
= extractFloatx80Sign(a
);
810 if (aExp
== 0x7FFF) {
811 if ((uint64_t) (aSig
<< 1)) {
812 return propagateFloatx80NaNOneArg(a
, status
);
815 return packFloatx80(0, 0, 0);
817 return packFloatx80(0, floatx80_infinity
.high
,
818 floatx80_infinity
.low
);
821 if (aExp
== 0 && aSig
== 0) {
822 return packFloatx80(0, one_exp
, one_sig
);
825 user_rnd_mode
= status
->float_rounding_mode
;
826 user_rnd_prec
= status
->floatx80_rounding_precision
;
827 status
->float_rounding_mode
= float_round_nearest_even
;
828 status
->floatx80_rounding_precision
= 80;
832 if (aExp
>= 0x3FBE) { /* |X| >= 2^(-65) */
833 compact
= floatx80_make_compact(aExp
, aSig
);
835 if (compact
< 0x400CB167) { /* |X| < 16380 log2 */
838 fp0
= floatx80_mul(fp0
, float32_to_floatx80(
839 make_float32(0x42B8AA3B), status
),
840 status
); /* 64/log2 * X */
842 n
= floatx80_to_int32(fp0
, status
); /* int(64/log2*X) */
843 fp0
= int32_to_floatx80(n
, status
);
845 j
= n
& 0x3F; /* J = N mod 64 */
846 m
= n
/ 64; /* NOTE: this is really arithmetic right shift by 6 */
848 /* arithmetic right shift is division and
849 * round towards minus infinity
853 m
+= 0x3FFF; /* biased exponent of 2^(M) */
857 fp0
= floatx80_mul(fp0
, float32_to_floatx80(
858 make_float32(0xBC317218), status
),
859 status
); /* N * L1, L1 = lead(-log2/64) */
860 l2
= packFloatx80(0, 0x3FDC, LIT64(0x82E308654361C4C6));
861 fp2
= floatx80_mul(fp2
, l2
, status
); /* N * L2, L1+L2 = -log2/64 */
862 fp0
= floatx80_add(fp0
, fp1
, status
); /* X + N*L1 */
863 fp0
= floatx80_add(fp0
, fp2
, status
); /* R */
865 fp1
= floatx80_mul(fp0
, fp0
, status
); /* S = R*R */
866 fp2
= float32_to_floatx80(make_float32(0x3AB60B70),
868 fp2
= floatx80_mul(fp2
, fp1
, status
); /* fp2 is S*A5 */
869 fp3
= floatx80_mul(float32_to_floatx80(make_float32(0x3C088895),
871 status
); /* fp3 is S*A4 */
872 fp2
= floatx80_add(fp2
, float64_to_floatx80(make_float64(
873 0x3FA5555555554431), status
),
874 status
); /* fp2 is A3+S*A5 */
875 fp3
= floatx80_add(fp3
, float64_to_floatx80(make_float64(
876 0x3FC5555555554018), status
),
877 status
); /* fp3 is A2+S*A4 */
878 fp2
= floatx80_mul(fp2
, fp1
, status
); /* fp2 is S*(A3+S*A5) */
879 fp3
= floatx80_mul(fp3
, fp1
, status
); /* fp3 is S*(A2+S*A4) */
880 fp2
= floatx80_add(fp2
, float32_to_floatx80(
881 make_float32(0x3F000000), status
),
882 status
); /* fp2 is A1+S*(A3+S*A5) */
883 fp3
= floatx80_mul(fp3
, fp0
, status
); /* fp3 IS R*S*(A2+S*A4) */
884 fp2
= floatx80_mul(fp2
, fp1
,
885 status
); /* fp2 IS S*(A1+S*(A3+S*A5)) */
886 fp0
= floatx80_add(fp0
, fp3
, status
); /* fp0 IS R+R*S*(A2+S*A4) */
887 fp0
= floatx80_add(fp0
, fp2
, status
); /* fp0 IS EXP(R) - 1 */
890 fp0
= floatx80_mul(fp0
, fp1
, status
); /* 2^(J/64)*(Exp(R)-1) */
891 fp0
= floatx80_add(fp0
, float32_to_floatx80(exp_tbl2
[j
], status
),
892 status
); /* accurate 2^(J/64) */
893 fp0
= floatx80_add(fp0
, fp1
,
894 status
); /* 2^(J/64) + 2^(J/64)*(Exp(R)-1) */
896 scale
= packFloatx80(0, m
, one_sig
);
898 adjscale
= packFloatx80(0, m1
, one_sig
);
899 fp0
= floatx80_mul(fp0
, adjscale
, status
);
902 status
->float_rounding_mode
= user_rnd_mode
;
903 status
->floatx80_rounding_precision
= user_rnd_prec
;
905 a
= floatx80_mul(fp0
, scale
, status
);
907 float_raise(float_flag_inexact
, status
);
910 } else { /* |X| >= 16380 log2 */
911 if (compact
> 0x400CB27C) { /* |X| >= 16480 log2 */
912 status
->float_rounding_mode
= user_rnd_mode
;
913 status
->floatx80_rounding_precision
= user_rnd_prec
;
915 a
= roundAndPackFloatx80(
916 status
->floatx80_rounding_precision
,
917 0, -0x1000, aSig
, 0, status
);
919 a
= roundAndPackFloatx80(
920 status
->floatx80_rounding_precision
,
921 0, 0x8000, aSig
, 0, status
);
923 float_raise(float_flag_inexact
, status
);
929 fp0
= floatx80_mul(fp0
, float32_to_floatx80(
930 make_float32(0x42B8AA3B), status
),
931 status
); /* 64/log2 * X */
933 n
= floatx80_to_int32(fp0
, status
); /* int(64/log2*X) */
934 fp0
= int32_to_floatx80(n
, status
);
936 j
= n
& 0x3F; /* J = N mod 64 */
937 /* NOTE: this is really arithmetic right shift by 6 */
940 /* arithmetic right shift is division and
941 * round towards minus infinity
945 /* NOTE: this is really arithmetic right shift by 1 */
947 if (k
< 0 && (k
& 1)) {
948 /* arithmetic right shift is division and
949 * round towards minus infinity
954 m1
+= 0x3FFF; /* biased exponent of 2^(M1) */
955 m
+= 0x3FFF; /* biased exponent of 2^(M) */
960 } else { /* |X| < 2^(-65) */
961 status
->float_rounding_mode
= user_rnd_mode
;
962 status
->floatx80_rounding_precision
= user_rnd_prec
;
964 a
= floatx80_add(a
, float32_to_floatx80(make_float32(0x3F800000),
965 status
), status
); /* 1 + X */
967 float_raise(float_flag_inexact
, status
);
973 /*----------------------------------------------------------------------------
975 *----------------------------------------------------------------------------*/
977 floatx80
floatx80_twotox(floatx80 a
, float_status
*status
)
983 int8_t user_rnd_mode
, user_rnd_prec
;
985 int32_t compact
, n
, j
, l
, m
, m1
;
986 floatx80 fp0
, fp1
, fp2
, fp3
, adjfact
, fact1
, fact2
;
988 aSig
= extractFloatx80Frac(a
);
989 aExp
= extractFloatx80Exp(a
);
990 aSign
= extractFloatx80Sign(a
);
992 if (aExp
== 0x7FFF) {
993 if ((uint64_t) (aSig
<< 1)) {
994 return propagateFloatx80NaNOneArg(a
, status
);
997 return packFloatx80(0, 0, 0);
999 return packFloatx80(0, floatx80_infinity
.high
,
1000 floatx80_infinity
.low
);
1003 if (aExp
== 0 && aSig
== 0) {
1004 return packFloatx80(0, one_exp
, one_sig
);
1007 user_rnd_mode
= status
->float_rounding_mode
;
1008 user_rnd_prec
= status
->floatx80_rounding_precision
;
1009 status
->float_rounding_mode
= float_round_nearest_even
;
1010 status
->floatx80_rounding_precision
= 80;
1014 compact
= floatx80_make_compact(aExp
, aSig
);
1016 if (compact
< 0x3FB98000 || compact
> 0x400D80C0) {
1017 /* |X| > 16480 or |X| < 2^(-70) */
1018 if (compact
> 0x3FFF8000) { /* |X| > 16480 */
1019 status
->float_rounding_mode
= user_rnd_mode
;
1020 status
->floatx80_rounding_precision
= user_rnd_prec
;
1023 return roundAndPackFloatx80(status
->floatx80_rounding_precision
,
1024 0, -0x1000, aSig
, 0, status
);
1026 return roundAndPackFloatx80(status
->floatx80_rounding_precision
,
1027 0, 0x8000, aSig
, 0, status
);
1029 } else { /* |X| < 2^(-70) */
1030 status
->float_rounding_mode
= user_rnd_mode
;
1031 status
->floatx80_rounding_precision
= user_rnd_prec
;
1033 a
= floatx80_add(fp0
, float32_to_floatx80(
1034 make_float32(0x3F800000), status
),
1035 status
); /* 1 + X */
1037 float_raise(float_flag_inexact
, status
);
1041 } else { /* 2^(-70) <= |X| <= 16480 */
1043 fp1
= floatx80_mul(fp1
, float32_to_floatx80(
1044 make_float32(0x42800000), status
),
1045 status
); /* X * 64 */
1046 n
= floatx80_to_int32(fp1
, status
);
1047 fp1
= int32_to_floatx80(n
, status
);
1049 l
= n
/ 64; /* NOTE: this is really arithmetic right shift by 6 */
1051 /* arithmetic right shift is division and
1052 * round towards minus infinity
1056 m
= l
/ 2; /* NOTE: this is really arithmetic right shift by 1 */
1057 if (l
< 0 && (l
& 1)) {
1058 /* arithmetic right shift is division and
1059 * round towards minus infinity
1064 m1
+= 0x3FFF; /* ADJFACT IS 2^(M') */
1066 adjfact
= packFloatx80(0, m1
, one_sig
);
1067 fact1
= exp2_tbl
[j
];
1069 fact2
.high
= exp2_tbl2
[j
] >> 16;
1071 fact2
.low
= (uint64_t)(exp2_tbl2
[j
] & 0xFFFF);
1074 fp1
= floatx80_mul(fp1
, float32_to_floatx80(
1075 make_float32(0x3C800000), status
),
1076 status
); /* (1/64)*N */
1077 fp0
= floatx80_sub(fp0
, fp1
, status
); /* X - (1/64)*INT(64 X) */
1078 fp2
= packFloatx80(0, 0x3FFE, LIT64(0xB17217F7D1CF79AC)); /* LOG2 */
1079 fp0
= floatx80_mul(fp0
, fp2
, status
); /* R */
1082 fp1
= floatx80_mul(fp0
, fp0
, status
); /* S = R*R */
1083 fp2
= float64_to_floatx80(make_float64(0x3F56C16D6F7BD0B2),
1085 fp3
= float64_to_floatx80(make_float64(0x3F811112302C712C),
1087 fp2
= floatx80_mul(fp2
, fp1
, status
); /* S*A5 */
1088 fp3
= floatx80_mul(fp3
, fp1
, status
); /* S*A4 */
1089 fp2
= floatx80_add(fp2
, float64_to_floatx80(
1090 make_float64(0x3FA5555555554CC1), status
),
1091 status
); /* A3+S*A5 */
1092 fp3
= floatx80_add(fp3
, float64_to_floatx80(
1093 make_float64(0x3FC5555555554A54), status
),
1094 status
); /* A2+S*A4 */
1095 fp2
= floatx80_mul(fp2
, fp1
, status
); /* S*(A3+S*A5) */
1096 fp3
= floatx80_mul(fp3
, fp1
, status
); /* S*(A2+S*A4) */
1097 fp2
= floatx80_add(fp2
, float64_to_floatx80(
1098 make_float64(0x3FE0000000000000), status
),
1099 status
); /* A1+S*(A3+S*A5) */
1100 fp3
= floatx80_mul(fp3
, fp0
, status
); /* R*S*(A2+S*A4) */
1102 fp2
= floatx80_mul(fp2
, fp1
, status
); /* S*(A1+S*(A3+S*A5)) */
1103 fp0
= floatx80_add(fp0
, fp3
, status
); /* R+R*S*(A2+S*A4) */
1104 fp0
= floatx80_add(fp0
, fp2
, status
); /* EXP(R) - 1 */
1106 fp0
= floatx80_mul(fp0
, fact1
, status
);
1107 fp0
= floatx80_add(fp0
, fact2
, status
);
1108 fp0
= floatx80_add(fp0
, fact1
, status
);
1110 status
->float_rounding_mode
= user_rnd_mode
;
1111 status
->floatx80_rounding_precision
= user_rnd_prec
;
1113 a
= floatx80_mul(fp0
, adjfact
, status
);
1115 float_raise(float_flag_inexact
, status
);
1121 /*----------------------------------------------------------------------------
1123 *----------------------------------------------------------------------------*/
1125 floatx80
floatx80_tentox(floatx80 a
, float_status
*status
)
1131 int8_t user_rnd_mode
, user_rnd_prec
;
1133 int32_t compact
, n
, j
, l
, m
, m1
;
1134 floatx80 fp0
, fp1
, fp2
, fp3
, adjfact
, fact1
, fact2
;
1136 aSig
= extractFloatx80Frac(a
);
1137 aExp
= extractFloatx80Exp(a
);
1138 aSign
= extractFloatx80Sign(a
);
1140 if (aExp
== 0x7FFF) {
1141 if ((uint64_t) (aSig
<< 1)) {
1142 return propagateFloatx80NaNOneArg(a
, status
);
1145 return packFloatx80(0, 0, 0);
1147 return packFloatx80(0, floatx80_infinity
.high
,
1148 floatx80_infinity
.low
);
1151 if (aExp
== 0 && aSig
== 0) {
1152 return packFloatx80(0, one_exp
, one_sig
);
1155 user_rnd_mode
= status
->float_rounding_mode
;
1156 user_rnd_prec
= status
->floatx80_rounding_precision
;
1157 status
->float_rounding_mode
= float_round_nearest_even
;
1158 status
->floatx80_rounding_precision
= 80;
1162 compact
= floatx80_make_compact(aExp
, aSig
);
1164 if (compact
< 0x3FB98000 || compact
> 0x400B9B07) {
1165 /* |X| > 16480 LOG2/LOG10 or |X| < 2^(-70) */
1166 if (compact
> 0x3FFF8000) { /* |X| > 16480 */
1167 status
->float_rounding_mode
= user_rnd_mode
;
1168 status
->floatx80_rounding_precision
= user_rnd_prec
;
1171 return roundAndPackFloatx80(status
->floatx80_rounding_precision
,
1172 0, -0x1000, aSig
, 0, status
);
1174 return roundAndPackFloatx80(status
->floatx80_rounding_precision
,
1175 0, 0x8000, aSig
, 0, status
);
1177 } else { /* |X| < 2^(-70) */
1178 status
->float_rounding_mode
= user_rnd_mode
;
1179 status
->floatx80_rounding_precision
= user_rnd_prec
;
1181 a
= floatx80_add(fp0
, float32_to_floatx80(
1182 make_float32(0x3F800000), status
),
1183 status
); /* 1 + X */
1185 float_raise(float_flag_inexact
, status
);
1189 } else { /* 2^(-70) <= |X| <= 16480 LOG 2 / LOG 10 */
1191 fp1
= floatx80_mul(fp1
, float64_to_floatx80(
1192 make_float64(0x406A934F0979A371),
1193 status
), status
); /* X*64*LOG10/LOG2 */
1194 n
= floatx80_to_int32(fp1
, status
); /* N=INT(X*64*LOG10/LOG2) */
1195 fp1
= int32_to_floatx80(n
, status
);
1198 l
= n
/ 64; /* NOTE: this is really arithmetic right shift by 6 */
1200 /* arithmetic right shift is division and
1201 * round towards minus infinity
1205 m
= l
/ 2; /* NOTE: this is really arithmetic right shift by 1 */
1206 if (l
< 0 && (l
& 1)) {
1207 /* arithmetic right shift is division and
1208 * round towards minus infinity
1213 m1
+= 0x3FFF; /* ADJFACT IS 2^(M') */
1215 adjfact
= packFloatx80(0, m1
, one_sig
);
1216 fact1
= exp2_tbl
[j
];
1218 fact2
.high
= exp2_tbl2
[j
] >> 16;
1220 fact2
.low
= (uint64_t)(exp2_tbl2
[j
] & 0xFFFF);
1224 fp1
= floatx80_mul(fp1
, float64_to_floatx80(
1225 make_float64(0x3F734413509F8000), status
),
1226 status
); /* N*(LOG2/64LOG10)_LEAD */
1227 fp3
= packFloatx80(1, 0x3FCD, LIT64(0xC0219DC1DA994FD2));
1228 fp2
= floatx80_mul(fp2
, fp3
, status
); /* N*(LOG2/64LOG10)_TRAIL */
1229 fp0
= floatx80_sub(fp0
, fp1
, status
); /* X - N L_LEAD */
1230 fp0
= floatx80_sub(fp0
, fp2
, status
); /* X - N L_TRAIL */
1231 fp2
= packFloatx80(0, 0x4000, LIT64(0x935D8DDDAAA8AC17)); /* LOG10 */
1232 fp0
= floatx80_mul(fp0
, fp2
, status
); /* R */
1235 fp1
= floatx80_mul(fp0
, fp0
, status
); /* S = R*R */
1236 fp2
= float64_to_floatx80(make_float64(0x3F56C16D6F7BD0B2),
1238 fp3
= float64_to_floatx80(make_float64(0x3F811112302C712C),
1240 fp2
= floatx80_mul(fp2
, fp1
, status
); /* S*A5 */
1241 fp3
= floatx80_mul(fp3
, fp1
, status
); /* S*A4 */
1242 fp2
= floatx80_add(fp2
, float64_to_floatx80(
1243 make_float64(0x3FA5555555554CC1), status
),
1244 status
); /* A3+S*A5 */
1245 fp3
= floatx80_add(fp3
, float64_to_floatx80(
1246 make_float64(0x3FC5555555554A54), status
),
1247 status
); /* A2+S*A4 */
1248 fp2
= floatx80_mul(fp2
, fp1
, status
); /* S*(A3+S*A5) */
1249 fp3
= floatx80_mul(fp3
, fp1
, status
); /* S*(A2+S*A4) */
1250 fp2
= floatx80_add(fp2
, float64_to_floatx80(
1251 make_float64(0x3FE0000000000000), status
),
1252 status
); /* A1+S*(A3+S*A5) */
1253 fp3
= floatx80_mul(fp3
, fp0
, status
); /* R*S*(A2+S*A4) */
1255 fp2
= floatx80_mul(fp2
, fp1
, status
); /* S*(A1+S*(A3+S*A5)) */
1256 fp0
= floatx80_add(fp0
, fp3
, status
); /* R+R*S*(A2+S*A4) */
1257 fp0
= floatx80_add(fp0
, fp2
, status
); /* EXP(R) - 1 */
1259 fp0
= floatx80_mul(fp0
, fact1
, status
);
1260 fp0
= floatx80_add(fp0
, fact2
, status
);
1261 fp0
= floatx80_add(fp0
, fact1
, status
);
1263 status
->float_rounding_mode
= user_rnd_mode
;
1264 status
->floatx80_rounding_precision
= user_rnd_prec
;
1266 a
= floatx80_mul(fp0
, adjfact
, status
);
1268 float_raise(float_flag_inexact
, status
);
1274 /*----------------------------------------------------------------------------
1276 *----------------------------------------------------------------------------*/
1278 floatx80
floatx80_tan(floatx80 a
, float_status
*status
)
1282 uint64_t aSig
, xSig
;
1284 int8_t user_rnd_mode
, user_rnd_prec
;
1286 int32_t compact
, l
, n
, j
;
1287 floatx80 fp0
, fp1
, fp2
, fp3
, fp4
, fp5
, invtwopi
, twopi1
, twopi2
;
1291 aSig
= extractFloatx80Frac(a
);
1292 aExp
= extractFloatx80Exp(a
);
1293 aSign
= extractFloatx80Sign(a
);
1295 if (aExp
== 0x7FFF) {
1296 if ((uint64_t) (aSig
<< 1)) {
1297 return propagateFloatx80NaNOneArg(a
, status
);
1299 float_raise(float_flag_invalid
, status
);
1300 return floatx80_default_nan(status
);
1303 if (aExp
== 0 && aSig
== 0) {
1304 return packFloatx80(aSign
, 0, 0);
1307 user_rnd_mode
= status
->float_rounding_mode
;
1308 user_rnd_prec
= status
->floatx80_rounding_precision
;
1309 status
->float_rounding_mode
= float_round_nearest_even
;
1310 status
->floatx80_rounding_precision
= 80;
1312 compact
= floatx80_make_compact(aExp
, aSig
);
1316 if (compact
< 0x3FD78000 || compact
> 0x4004BC7E) {
1317 /* 2^(-40) > |X| > 15 PI */
1318 if (compact
> 0x3FFF8000) { /* |X| >= 15 PI */
1320 fp1
= packFloatx80(0, 0, 0);
1321 if (compact
== 0x7FFEFFFF) {
1322 twopi1
= packFloatx80(aSign
^ 1, 0x7FFE,
1323 LIT64(0xC90FDAA200000000));
1324 twopi2
= packFloatx80(aSign
^ 1, 0x7FDC,
1325 LIT64(0x85A308D300000000));
1326 fp0
= floatx80_add(fp0
, twopi1
, status
);
1328 fp0
= floatx80_add(fp0
, twopi2
, status
);
1329 fp1
= floatx80_sub(fp1
, fp0
, status
);
1330 fp1
= floatx80_add(fp1
, twopi2
, status
);
1333 xSign
= extractFloatx80Sign(fp0
);
1334 xExp
= extractFloatx80Exp(fp0
);
1343 invtwopi
= packFloatx80(0, 0x3FFE - l
,
1344 LIT64(0xA2F9836E4E44152A)); /* INVTWOPI */
1345 twopi1
= packFloatx80(0, 0x3FFF + l
, LIT64(0xC90FDAA200000000));
1346 twopi2
= packFloatx80(0, 0x3FDD + l
, LIT64(0x85A308D300000000));
1348 /* SIGN(INARG)*2^63 IN SGL */
1349 twoto63
= packFloat32(xSign
, 0xBE, 0);
1351 fp2
= floatx80_mul(fp0
, invtwopi
, status
);
1352 fp2
= floatx80_add(fp2
, float32_to_floatx80(twoto63
, status
),
1353 status
); /* THE FRACT PART OF FP2 IS ROUNDED */
1354 fp2
= floatx80_sub(fp2
, float32_to_floatx80(twoto63
, status
),
1355 status
); /* FP2 is N */
1356 fp4
= floatx80_mul(twopi1
, fp2
, status
); /* W = N*P1 */
1357 fp5
= floatx80_mul(twopi2
, fp2
, status
); /* w = N*P2 */
1358 fp3
= floatx80_add(fp4
, fp5
, status
); /* FP3 is P */
1359 fp4
= floatx80_sub(fp4
, fp3
, status
); /* W-P */
1360 fp0
= floatx80_sub(fp0
, fp3
, status
); /* FP0 is A := R - P */
1361 fp4
= floatx80_add(fp4
, fp5
, status
); /* FP4 is p = (W-P)+w */
1362 fp3
= fp0
; /* FP3 is A */
1363 fp1
= floatx80_sub(fp1
, fp4
, status
); /* FP1 is a := r - p */
1364 fp0
= floatx80_add(fp0
, fp1
, status
); /* FP0 is R := A+a */
1367 n
= floatx80_to_int32(fp2
, status
);
1370 fp3
= floatx80_sub(fp3
, fp0
, status
); /* A-R */
1371 fp1
= floatx80_add(fp1
, fp3
, status
); /* FP1 is r := (A-R)+a */
1374 status
->float_rounding_mode
= user_rnd_mode
;
1375 status
->floatx80_rounding_precision
= user_rnd_prec
;
1377 a
= floatx80_move(a
, status
);
1379 float_raise(float_flag_inexact
, status
);
1384 fp1
= floatx80_mul(fp0
, float64_to_floatx80(
1385 make_float64(0x3FE45F306DC9C883), status
),
1386 status
); /* X*2/PI */
1388 n
= floatx80_to_int32(fp1
, status
);
1391 fp0
= floatx80_sub(fp0
, pi_tbl
[j
], status
); /* X-Y1 */
1392 fp0
= floatx80_sub(fp0
, float32_to_floatx80(pi_tbl2
[j
], status
),
1393 status
); /* FP0 IS R = (X-Y1)-Y2 */
1399 fp0
= floatx80_mul(fp0
, fp0
, status
); /* S = R*R */
1400 fp3
= float64_to_floatx80(make_float64(0x3EA0B759F50F8688),
1402 fp2
= float64_to_floatx80(make_float64(0xBEF2BAA5A8924F04),
1404 fp3
= floatx80_mul(fp3
, fp0
, status
); /* SQ4 */
1405 fp2
= floatx80_mul(fp2
, fp0
, status
); /* SP3 */
1406 fp3
= floatx80_add(fp3
, float64_to_floatx80(
1407 make_float64(0xBF346F59B39BA65F), status
),
1408 status
); /* Q3+SQ4 */
1409 fp4
= packFloatx80(0, 0x3FF6, LIT64(0xE073D3FC199C4A00));
1410 fp2
= floatx80_add(fp2
, fp4
, status
); /* P2+SP3 */
1411 fp3
= floatx80_mul(fp3
, fp0
, status
); /* S(Q3+SQ4) */
1412 fp2
= floatx80_mul(fp2
, fp0
, status
); /* S(P2+SP3) */
1413 fp4
= packFloatx80(0, 0x3FF9, LIT64(0xD23CD68415D95FA1));
1414 fp3
= floatx80_add(fp3
, fp4
, status
); /* Q2+S(Q3+SQ4) */
1415 fp4
= packFloatx80(1, 0x3FFC, LIT64(0x8895A6C5FB423BCA));
1416 fp2
= floatx80_add(fp2
, fp4
, status
); /* P1+S(P2+SP3) */
1417 fp3
= floatx80_mul(fp3
, fp0
, status
); /* S(Q2+S(Q3+SQ4)) */
1418 fp2
= floatx80_mul(fp2
, fp0
, status
); /* S(P1+S(P2+SP3)) */
1419 fp4
= packFloatx80(1, 0x3FFD, LIT64(0xEEF57E0DA84BC8CE));
1420 fp3
= floatx80_add(fp3
, fp4
, status
); /* Q1+S(Q2+S(Q3+SQ4)) */
1421 fp2
= floatx80_mul(fp2
, fp1
, status
); /* RS(P1+S(P2+SP3)) */
1422 fp0
= floatx80_mul(fp0
, fp3
, status
); /* S(Q1+S(Q2+S(Q3+SQ4))) */
1423 fp1
= floatx80_add(fp1
, fp2
, status
); /* R+RS(P1+S(P2+SP3)) */
1424 fp0
= floatx80_add(fp0
, float32_to_floatx80(
1425 make_float32(0x3F800000), status
),
1426 status
); /* 1+S(Q1+S(Q2+S(Q3+SQ4))) */
1428 xSign
= extractFloatx80Sign(fp1
);
1429 xExp
= extractFloatx80Exp(fp1
);
1430 xSig
= extractFloatx80Frac(fp1
);
1432 fp1
= packFloatx80(xSign
, xExp
, xSig
);
1434 status
->float_rounding_mode
= user_rnd_mode
;
1435 status
->floatx80_rounding_precision
= user_rnd_prec
;
1437 a
= floatx80_div(fp0
, fp1
, status
);
1439 float_raise(float_flag_inexact
, status
);
1443 fp1
= floatx80_mul(fp0
, fp0
, status
); /* S = R*R */
1444 fp3
= float64_to_floatx80(make_float64(0x3EA0B759F50F8688),
1446 fp2
= float64_to_floatx80(make_float64(0xBEF2BAA5A8924F04),
1448 fp3
= floatx80_mul(fp3
, fp1
, status
); /* SQ4 */
1449 fp2
= floatx80_mul(fp2
, fp1
, status
); /* SP3 */
1450 fp3
= floatx80_add(fp3
, float64_to_floatx80(
1451 make_float64(0xBF346F59B39BA65F), status
),
1452 status
); /* Q3+SQ4 */
1453 fp4
= packFloatx80(0, 0x3FF6, LIT64(0xE073D3FC199C4A00));
1454 fp2
= floatx80_add(fp2
, fp4
, status
); /* P2+SP3 */
1455 fp3
= floatx80_mul(fp3
, fp1
, status
); /* S(Q3+SQ4) */
1456 fp2
= floatx80_mul(fp2
, fp1
, status
); /* S(P2+SP3) */
1457 fp4
= packFloatx80(0, 0x3FF9, LIT64(0xD23CD68415D95FA1));
1458 fp3
= floatx80_add(fp3
, fp4
, status
); /* Q2+S(Q3+SQ4) */
1459 fp4
= packFloatx80(1, 0x3FFC, LIT64(0x8895A6C5FB423BCA));
1460 fp2
= floatx80_add(fp2
, fp4
, status
); /* P1+S(P2+SP3) */
1461 fp3
= floatx80_mul(fp3
, fp1
, status
); /* S(Q2+S(Q3+SQ4)) */
1462 fp2
= floatx80_mul(fp2
, fp1
, status
); /* S(P1+S(P2+SP3)) */
1463 fp4
= packFloatx80(1, 0x3FFD, LIT64(0xEEF57E0DA84BC8CE));
1464 fp3
= floatx80_add(fp3
, fp4
, status
); /* Q1+S(Q2+S(Q3+SQ4)) */
1465 fp2
= floatx80_mul(fp2
, fp0
, status
); /* RS(P1+S(P2+SP3)) */
1466 fp1
= floatx80_mul(fp1
, fp3
, status
); /* S(Q1+S(Q2+S(Q3+SQ4))) */
1467 fp0
= floatx80_add(fp0
, fp2
, status
); /* R+RS(P1+S(P2+SP3)) */
1468 fp1
= floatx80_add(fp1
, float32_to_floatx80(
1469 make_float32(0x3F800000), status
),
1470 status
); /* 1+S(Q1+S(Q2+S(Q3+SQ4))) */
1472 status
->float_rounding_mode
= user_rnd_mode
;
1473 status
->floatx80_rounding_precision
= user_rnd_prec
;
1475 a
= floatx80_div(fp0
, fp1
, status
);
1477 float_raise(float_flag_inexact
, status
);
1484 /*----------------------------------------------------------------------------
1486 *----------------------------------------------------------------------------*/
1488 floatx80
floatx80_sin(floatx80 a
, float_status
*status
)
1492 uint64_t aSig
, xSig
;
1494 int8_t user_rnd_mode
, user_rnd_prec
;
1496 int32_t compact
, l
, n
, j
;
1497 floatx80 fp0
, fp1
, fp2
, fp3
, fp4
, fp5
, x
, invtwopi
, twopi1
, twopi2
;
1498 float32 posneg1
, twoto63
;
1501 aSig
= extractFloatx80Frac(a
);
1502 aExp
= extractFloatx80Exp(a
);
1503 aSign
= extractFloatx80Sign(a
);
1505 if (aExp
== 0x7FFF) {
1506 if ((uint64_t) (aSig
<< 1)) {
1507 return propagateFloatx80NaNOneArg(a
, status
);
1509 float_raise(float_flag_invalid
, status
);
1510 return floatx80_default_nan(status
);
1513 if (aExp
== 0 && aSig
== 0) {
1514 return packFloatx80(aSign
, 0, 0);
1519 user_rnd_mode
= status
->float_rounding_mode
;
1520 user_rnd_prec
= status
->floatx80_rounding_precision
;
1521 status
->float_rounding_mode
= float_round_nearest_even
;
1522 status
->floatx80_rounding_precision
= 80;
1524 compact
= floatx80_make_compact(aExp
, aSig
);
1528 if (compact
< 0x3FD78000 || compact
> 0x4004BC7E) {
1529 /* 2^(-40) > |X| > 15 PI */
1530 if (compact
> 0x3FFF8000) { /* |X| >= 15 PI */
1532 fp1
= packFloatx80(0, 0, 0);
1533 if (compact
== 0x7FFEFFFF) {
1534 twopi1
= packFloatx80(aSign
^ 1, 0x7FFE,
1535 LIT64(0xC90FDAA200000000));
1536 twopi2
= packFloatx80(aSign
^ 1, 0x7FDC,
1537 LIT64(0x85A308D300000000));
1538 fp0
= floatx80_add(fp0
, twopi1
, status
);
1540 fp0
= floatx80_add(fp0
, twopi2
, status
);
1541 fp1
= floatx80_sub(fp1
, fp0
, status
);
1542 fp1
= floatx80_add(fp1
, twopi2
, status
);
1545 xSign
= extractFloatx80Sign(fp0
);
1546 xExp
= extractFloatx80Exp(fp0
);
1555 invtwopi
= packFloatx80(0, 0x3FFE - l
,
1556 LIT64(0xA2F9836E4E44152A)); /* INVTWOPI */
1557 twopi1
= packFloatx80(0, 0x3FFF + l
, LIT64(0xC90FDAA200000000));
1558 twopi2
= packFloatx80(0, 0x3FDD + l
, LIT64(0x85A308D300000000));
1560 /* SIGN(INARG)*2^63 IN SGL */
1561 twoto63
= packFloat32(xSign
, 0xBE, 0);
1563 fp2
= floatx80_mul(fp0
, invtwopi
, status
);
1564 fp2
= floatx80_add(fp2
, float32_to_floatx80(twoto63
, status
),
1565 status
); /* THE FRACT PART OF FP2 IS ROUNDED */
1566 fp2
= floatx80_sub(fp2
, float32_to_floatx80(twoto63
, status
),
1567 status
); /* FP2 is N */
1568 fp4
= floatx80_mul(twopi1
, fp2
, status
); /* W = N*P1 */
1569 fp5
= floatx80_mul(twopi2
, fp2
, status
); /* w = N*P2 */
1570 fp3
= floatx80_add(fp4
, fp5
, status
); /* FP3 is P */
1571 fp4
= floatx80_sub(fp4
, fp3
, status
); /* W-P */
1572 fp0
= floatx80_sub(fp0
, fp3
, status
); /* FP0 is A := R - P */
1573 fp4
= floatx80_add(fp4
, fp5
, status
); /* FP4 is p = (W-P)+w */
1574 fp3
= fp0
; /* FP3 is A */
1575 fp1
= floatx80_sub(fp1
, fp4
, status
); /* FP1 is a := r - p */
1576 fp0
= floatx80_add(fp0
, fp1
, status
); /* FP0 is R := A+a */
1579 n
= floatx80_to_int32(fp2
, status
);
1582 fp3
= floatx80_sub(fp3
, fp0
, status
); /* A-R */
1583 fp1
= floatx80_add(fp1
, fp3
, status
); /* FP1 is r := (A-R)+a */
1587 fp0
= float32_to_floatx80(make_float32(0x3F800000),
1590 status
->float_rounding_mode
= user_rnd_mode
;
1591 status
->floatx80_rounding_precision
= user_rnd_prec
;
1595 a
= floatx80_sub(fp0
, float32_to_floatx80(
1596 make_float32(0x00800000), status
), status
);
1599 a
= floatx80_move(a
, status
);
1601 float_raise(float_flag_inexact
, status
);
1606 fp1
= floatx80_mul(fp0
, float64_to_floatx80(
1607 make_float64(0x3FE45F306DC9C883), status
),
1608 status
); /* X*2/PI */
1610 n
= floatx80_to_int32(fp1
, status
);
1613 fp0
= floatx80_sub(fp0
, pi_tbl
[j
], status
); /* X-Y1 */
1614 fp0
= floatx80_sub(fp0
, float32_to_floatx80(pi_tbl2
[j
], status
),
1615 status
); /* FP0 IS R = (X-Y1)-Y2 */
1618 if ((n
+ adjn
) & 1) {
1620 fp0
= floatx80_mul(fp0
, fp0
, status
); /* FP0 IS S */
1621 fp1
= floatx80_mul(fp0
, fp0
, status
); /* FP1 IS T */
1622 fp2
= float64_to_floatx80(make_float64(0x3D2AC4D0D6011EE3),
1624 fp3
= float64_to_floatx80(make_float64(0xBDA9396F9F45AC19),
1627 xSign
= extractFloatx80Sign(fp0
); /* X IS S */
1628 xExp
= extractFloatx80Exp(fp0
);
1629 xSig
= extractFloatx80Frac(fp0
);
1631 if (((n
+ adjn
) >> 1) & 1) {
1633 posneg1
= make_float32(0xBF800000); /* -1 */
1636 posneg1
= make_float32(0x3F800000); /* 1 */
1637 } /* X IS NOW R'= SGN*R */
1639 fp2
= floatx80_mul(fp2
, fp1
, status
); /* TB8 */
1640 fp3
= floatx80_mul(fp3
, fp1
, status
); /* TB7 */
1641 fp2
= floatx80_add(fp2
, float64_to_floatx80(
1642 make_float64(0x3E21EED90612C972), status
),
1643 status
); /* B6+TB8 */
1644 fp3
= floatx80_add(fp3
, float64_to_floatx80(
1645 make_float64(0xBE927E4FB79D9FCF), status
),
1646 status
); /* B5+TB7 */
1647 fp2
= floatx80_mul(fp2
, fp1
, status
); /* T(B6+TB8) */
1648 fp3
= floatx80_mul(fp3
, fp1
, status
); /* T(B5+TB7) */
1649 fp2
= floatx80_add(fp2
, float64_to_floatx80(
1650 make_float64(0x3EFA01A01A01D423), status
),
1651 status
); /* B4+T(B6+TB8) */
1652 fp4
= packFloatx80(1, 0x3FF5, LIT64(0xB60B60B60B61D438));
1653 fp3
= floatx80_add(fp3
, fp4
, status
); /* B3+T(B5+TB7) */
1654 fp2
= floatx80_mul(fp2
, fp1
, status
); /* T(B4+T(B6+TB8)) */
1655 fp1
= floatx80_mul(fp1
, fp3
, status
); /* T(B3+T(B5+TB7)) */
1656 fp4
= packFloatx80(0, 0x3FFA, LIT64(0xAAAAAAAAAAAAAB5E));
1657 fp2
= floatx80_add(fp2
, fp4
, status
); /* B2+T(B4+T(B6+TB8)) */
1658 fp1
= floatx80_add(fp1
, float32_to_floatx80(
1659 make_float32(0xBF000000), status
),
1660 status
); /* B1+T(B3+T(B5+TB7)) */
1661 fp0
= floatx80_mul(fp0
, fp2
, status
); /* S(B2+T(B4+T(B6+TB8))) */
1662 fp0
= floatx80_add(fp0
, fp1
, status
); /* [B1+T(B3+T(B5+TB7))]+
1663 * [S(B2+T(B4+T(B6+TB8)))]
1666 x
= packFloatx80(xSign
, xExp
, xSig
);
1667 fp0
= floatx80_mul(fp0
, x
, status
);
1669 status
->float_rounding_mode
= user_rnd_mode
;
1670 status
->floatx80_rounding_precision
= user_rnd_prec
;
1672 a
= floatx80_add(fp0
, float32_to_floatx80(posneg1
, status
), status
);
1674 float_raise(float_flag_inexact
, status
);
1679 xSign
= extractFloatx80Sign(fp0
); /* X IS R */
1680 xExp
= extractFloatx80Exp(fp0
);
1681 xSig
= extractFloatx80Frac(fp0
);
1683 xSign
^= ((n
+ adjn
) >> 1) & 1; /* X IS NOW R'= SGN*R */
1685 fp0
= floatx80_mul(fp0
, fp0
, status
); /* FP0 IS S */
1686 fp1
= floatx80_mul(fp0
, fp0
, status
); /* FP1 IS T */
1687 fp3
= float64_to_floatx80(make_float64(0xBD6AAA77CCC994F5),
1689 fp2
= float64_to_floatx80(make_float64(0x3DE612097AAE8DA1),
1691 fp3
= floatx80_mul(fp3
, fp1
, status
); /* T*A7 */
1692 fp2
= floatx80_mul(fp2
, fp1
, status
); /* T*A6 */
1693 fp3
= floatx80_add(fp3
, float64_to_floatx80(
1694 make_float64(0xBE5AE6452A118AE4), status
),
1695 status
); /* A5+T*A7 */
1696 fp2
= floatx80_add(fp2
, float64_to_floatx80(
1697 make_float64(0x3EC71DE3A5341531), status
),
1698 status
); /* A4+T*A6 */
1699 fp3
= floatx80_mul(fp3
, fp1
, status
); /* T(A5+TA7) */
1700 fp2
= floatx80_mul(fp2
, fp1
, status
); /* T(A4+TA6) */
1701 fp3
= floatx80_add(fp3
, float64_to_floatx80(
1702 make_float64(0xBF2A01A01A018B59), status
),
1703 status
); /* A3+T(A5+TA7) */
1704 fp4
= packFloatx80(0, 0x3FF8, LIT64(0x88888888888859AF));
1705 fp2
= floatx80_add(fp2
, fp4
, status
); /* A2+T(A4+TA6) */
1706 fp1
= floatx80_mul(fp1
, fp3
, status
); /* T(A3+T(A5+TA7)) */
1707 fp2
= floatx80_mul(fp2
, fp0
, status
); /* S(A2+T(A4+TA6)) */
1708 fp4
= packFloatx80(1, 0x3FFC, LIT64(0xAAAAAAAAAAAAAA99));
1709 fp1
= floatx80_add(fp1
, fp4
, status
); /* A1+T(A3+T(A5+TA7)) */
1710 fp1
= floatx80_add(fp1
, fp2
,
1711 status
); /* [A1+T(A3+T(A5+TA7))]+
1715 x
= packFloatx80(xSign
, xExp
, xSig
);
1716 fp0
= floatx80_mul(fp0
, x
, status
); /* R'*S */
1717 fp0
= floatx80_mul(fp0
, fp1
, status
); /* SIN(R')-R' */
1719 status
->float_rounding_mode
= user_rnd_mode
;
1720 status
->floatx80_rounding_precision
= user_rnd_prec
;
1722 a
= floatx80_add(fp0
, x
, status
);
1724 float_raise(float_flag_inexact
, status
);
1731 /*----------------------------------------------------------------------------
1733 *----------------------------------------------------------------------------*/
1735 floatx80
floatx80_cos(floatx80 a
, float_status
*status
)
1739 uint64_t aSig
, xSig
;
1741 int8_t user_rnd_mode
, user_rnd_prec
;
1743 int32_t compact
, l
, n
, j
;
1744 floatx80 fp0
, fp1
, fp2
, fp3
, fp4
, fp5
, x
, invtwopi
, twopi1
, twopi2
;
1745 float32 posneg1
, twoto63
;
1748 aSig
= extractFloatx80Frac(a
);
1749 aExp
= extractFloatx80Exp(a
);
1750 aSign
= extractFloatx80Sign(a
);
1752 if (aExp
== 0x7FFF) {
1753 if ((uint64_t) (aSig
<< 1)) {
1754 return propagateFloatx80NaNOneArg(a
, status
);
1756 float_raise(float_flag_invalid
, status
);
1757 return floatx80_default_nan(status
);
1760 if (aExp
== 0 && aSig
== 0) {
1761 return packFloatx80(0, one_exp
, one_sig
);
1766 user_rnd_mode
= status
->float_rounding_mode
;
1767 user_rnd_prec
= status
->floatx80_rounding_precision
;
1768 status
->float_rounding_mode
= float_round_nearest_even
;
1769 status
->floatx80_rounding_precision
= 80;
1771 compact
= floatx80_make_compact(aExp
, aSig
);
1775 if (compact
< 0x3FD78000 || compact
> 0x4004BC7E) {
1776 /* 2^(-40) > |X| > 15 PI */
1777 if (compact
> 0x3FFF8000) { /* |X| >= 15 PI */
1779 fp1
= packFloatx80(0, 0, 0);
1780 if (compact
== 0x7FFEFFFF) {
1781 twopi1
= packFloatx80(aSign
^ 1, 0x7FFE,
1782 LIT64(0xC90FDAA200000000));
1783 twopi2
= packFloatx80(aSign
^ 1, 0x7FDC,
1784 LIT64(0x85A308D300000000));
1785 fp0
= floatx80_add(fp0
, twopi1
, status
);
1787 fp0
= floatx80_add(fp0
, twopi2
, status
);
1788 fp1
= floatx80_sub(fp1
, fp0
, status
);
1789 fp1
= floatx80_add(fp1
, twopi2
, status
);
1792 xSign
= extractFloatx80Sign(fp0
);
1793 xExp
= extractFloatx80Exp(fp0
);
1802 invtwopi
= packFloatx80(0, 0x3FFE - l
,
1803 LIT64(0xA2F9836E4E44152A)); /* INVTWOPI */
1804 twopi1
= packFloatx80(0, 0x3FFF + l
, LIT64(0xC90FDAA200000000));
1805 twopi2
= packFloatx80(0, 0x3FDD + l
, LIT64(0x85A308D300000000));
1807 /* SIGN(INARG)*2^63 IN SGL */
1808 twoto63
= packFloat32(xSign
, 0xBE, 0);
1810 fp2
= floatx80_mul(fp0
, invtwopi
, status
);
1811 fp2
= floatx80_add(fp2
, float32_to_floatx80(twoto63
, status
),
1812 status
); /* THE FRACT PART OF FP2 IS ROUNDED */
1813 fp2
= floatx80_sub(fp2
, float32_to_floatx80(twoto63
, status
),
1814 status
); /* FP2 is N */
1815 fp4
= floatx80_mul(twopi1
, fp2
, status
); /* W = N*P1 */
1816 fp5
= floatx80_mul(twopi2
, fp2
, status
); /* w = N*P2 */
1817 fp3
= floatx80_add(fp4
, fp5
, status
); /* FP3 is P */
1818 fp4
= floatx80_sub(fp4
, fp3
, status
); /* W-P */
1819 fp0
= floatx80_sub(fp0
, fp3
, status
); /* FP0 is A := R - P */
1820 fp4
= floatx80_add(fp4
, fp5
, status
); /* FP4 is p = (W-P)+w */
1821 fp3
= fp0
; /* FP3 is A */
1822 fp1
= floatx80_sub(fp1
, fp4
, status
); /* FP1 is a := r - p */
1823 fp0
= floatx80_add(fp0
, fp1
, status
); /* FP0 is R := A+a */
1826 n
= floatx80_to_int32(fp2
, status
);
1829 fp3
= floatx80_sub(fp3
, fp0
, status
); /* A-R */
1830 fp1
= floatx80_add(fp1
, fp3
, status
); /* FP1 is r := (A-R)+a */
1834 fp0
= float32_to_floatx80(make_float32(0x3F800000), status
); /* 1 */
1836 status
->float_rounding_mode
= user_rnd_mode
;
1837 status
->floatx80_rounding_precision
= user_rnd_prec
;
1841 a
= floatx80_sub(fp0
, float32_to_floatx80(
1842 make_float32(0x00800000), status
),
1846 a
= floatx80_move(a
, status
);
1848 float_raise(float_flag_inexact
, status
);
1853 fp1
= floatx80_mul(fp0
, float64_to_floatx80(
1854 make_float64(0x3FE45F306DC9C883), status
),
1855 status
); /* X*2/PI */
1857 n
= floatx80_to_int32(fp1
, status
);
1860 fp0
= floatx80_sub(fp0
, pi_tbl
[j
], status
); /* X-Y1 */
1861 fp0
= floatx80_sub(fp0
, float32_to_floatx80(pi_tbl2
[j
], status
),
1862 status
); /* FP0 IS R = (X-Y1)-Y2 */
1865 if ((n
+ adjn
) & 1) {
1867 fp0
= floatx80_mul(fp0
, fp0
, status
); /* FP0 IS S */
1868 fp1
= floatx80_mul(fp0
, fp0
, status
); /* FP1 IS T */
1869 fp2
= float64_to_floatx80(make_float64(0x3D2AC4D0D6011EE3),
1871 fp3
= float64_to_floatx80(make_float64(0xBDA9396F9F45AC19),
1874 xSign
= extractFloatx80Sign(fp0
); /* X IS S */
1875 xExp
= extractFloatx80Exp(fp0
);
1876 xSig
= extractFloatx80Frac(fp0
);
1878 if (((n
+ adjn
) >> 1) & 1) {
1880 posneg1
= make_float32(0xBF800000); /* -1 */
1883 posneg1
= make_float32(0x3F800000); /* 1 */
1884 } /* X IS NOW R'= SGN*R */
1886 fp2
= floatx80_mul(fp2
, fp1
, status
); /* TB8 */
1887 fp3
= floatx80_mul(fp3
, fp1
, status
); /* TB7 */
1888 fp2
= floatx80_add(fp2
, float64_to_floatx80(
1889 make_float64(0x3E21EED90612C972), status
),
1890 status
); /* B6+TB8 */
1891 fp3
= floatx80_add(fp3
, float64_to_floatx80(
1892 make_float64(0xBE927E4FB79D9FCF), status
),
1893 status
); /* B5+TB7 */
1894 fp2
= floatx80_mul(fp2
, fp1
, status
); /* T(B6+TB8) */
1895 fp3
= floatx80_mul(fp3
, fp1
, status
); /* T(B5+TB7) */
1896 fp2
= floatx80_add(fp2
, float64_to_floatx80(
1897 make_float64(0x3EFA01A01A01D423), status
),
1898 status
); /* B4+T(B6+TB8) */
1899 fp4
= packFloatx80(1, 0x3FF5, LIT64(0xB60B60B60B61D438));
1900 fp3
= floatx80_add(fp3
, fp4
, status
); /* B3+T(B5+TB7) */
1901 fp2
= floatx80_mul(fp2
, fp1
, status
); /* T(B4+T(B6+TB8)) */
1902 fp1
= floatx80_mul(fp1
, fp3
, status
); /* T(B3+T(B5+TB7)) */
1903 fp4
= packFloatx80(0, 0x3FFA, LIT64(0xAAAAAAAAAAAAAB5E));
1904 fp2
= floatx80_add(fp2
, fp4
, status
); /* B2+T(B4+T(B6+TB8)) */
1905 fp1
= floatx80_add(fp1
, float32_to_floatx80(
1906 make_float32(0xBF000000), status
),
1907 status
); /* B1+T(B3+T(B5+TB7)) */
1908 fp0
= floatx80_mul(fp0
, fp2
, status
); /* S(B2+T(B4+T(B6+TB8))) */
1909 fp0
= floatx80_add(fp0
, fp1
, status
);
1910 /* [B1+T(B3+T(B5+TB7))]+[S(B2+T(B4+T(B6+TB8)))] */
1912 x
= packFloatx80(xSign
, xExp
, xSig
);
1913 fp0
= floatx80_mul(fp0
, x
, status
);
1915 status
->float_rounding_mode
= user_rnd_mode
;
1916 status
->floatx80_rounding_precision
= user_rnd_prec
;
1918 a
= floatx80_add(fp0
, float32_to_floatx80(posneg1
, status
), status
);
1920 float_raise(float_flag_inexact
, status
);
1925 xSign
= extractFloatx80Sign(fp0
); /* X IS R */
1926 xExp
= extractFloatx80Exp(fp0
);
1927 xSig
= extractFloatx80Frac(fp0
);
1929 xSign
^= ((n
+ adjn
) >> 1) & 1; /* X IS NOW R'= SGN*R */
1931 fp0
= floatx80_mul(fp0
, fp0
, status
); /* FP0 IS S */
1932 fp1
= floatx80_mul(fp0
, fp0
, status
); /* FP1 IS T */
1933 fp3
= float64_to_floatx80(make_float64(0xBD6AAA77CCC994F5),
1935 fp2
= float64_to_floatx80(make_float64(0x3DE612097AAE8DA1),
1937 fp3
= floatx80_mul(fp3
, fp1
, status
); /* T*A7 */
1938 fp2
= floatx80_mul(fp2
, fp1
, status
); /* T*A6 */
1939 fp3
= floatx80_add(fp3
, float64_to_floatx80(
1940 make_float64(0xBE5AE6452A118AE4), status
),
1941 status
); /* A5+T*A7 */
1942 fp2
= floatx80_add(fp2
, float64_to_floatx80(
1943 make_float64(0x3EC71DE3A5341531), status
),
1944 status
); /* A4+T*A6 */
1945 fp3
= floatx80_mul(fp3
, fp1
, status
); /* T(A5+TA7) */
1946 fp2
= floatx80_mul(fp2
, fp1
, status
); /* T(A4+TA6) */
1947 fp3
= floatx80_add(fp3
, float64_to_floatx80(
1948 make_float64(0xBF2A01A01A018B59), status
),
1949 status
); /* A3+T(A5+TA7) */
1950 fp4
= packFloatx80(0, 0x3FF8, LIT64(0x88888888888859AF));
1951 fp2
= floatx80_add(fp2
, fp4
, status
); /* A2+T(A4+TA6) */
1952 fp1
= floatx80_mul(fp1
, fp3
, status
); /* T(A3+T(A5+TA7)) */
1953 fp2
= floatx80_mul(fp2
, fp0
, status
); /* S(A2+T(A4+TA6)) */
1954 fp4
= packFloatx80(1, 0x3FFC, LIT64(0xAAAAAAAAAAAAAA99));
1955 fp1
= floatx80_add(fp1
, fp4
, status
); /* A1+T(A3+T(A5+TA7)) */
1956 fp1
= floatx80_add(fp1
, fp2
, status
);
1957 /* [A1+T(A3+T(A5+TA7))]+[S(A2+T(A4+TA6))] */
1959 x
= packFloatx80(xSign
, xExp
, xSig
);
1960 fp0
= floatx80_mul(fp0
, x
, status
); /* R'*S */
1961 fp0
= floatx80_mul(fp0
, fp1
, status
); /* SIN(R')-R' */
1963 status
->float_rounding_mode
= user_rnd_mode
;
1964 status
->floatx80_rounding_precision
= user_rnd_prec
;
1966 a
= floatx80_add(fp0
, x
, status
);
1968 float_raise(float_flag_inexact
, status
);
1975 /*----------------------------------------------------------------------------
1977 *----------------------------------------------------------------------------*/
1979 floatx80
floatx80_atan(floatx80 a
, float_status
*status
)
1985 int8_t user_rnd_mode
, user_rnd_prec
;
1987 int32_t compact
, tbl_index
;
1988 floatx80 fp0
, fp1
, fp2
, fp3
, xsave
;
1990 aSig
= extractFloatx80Frac(a
);
1991 aExp
= extractFloatx80Exp(a
);
1992 aSign
= extractFloatx80Sign(a
);
1994 if (aExp
== 0x7FFF) {
1995 if ((uint64_t) (aSig
<< 1)) {
1996 return propagateFloatx80NaNOneArg(a
, status
);
1998 a
= packFloatx80(aSign
, piby2_exp
, pi_sig
);
1999 float_raise(float_flag_inexact
, status
);
2000 return floatx80_move(a
, status
);
2003 if (aExp
== 0 && aSig
== 0) {
2004 return packFloatx80(aSign
, 0, 0);
2007 compact
= floatx80_make_compact(aExp
, aSig
);
2009 user_rnd_mode
= status
->float_rounding_mode
;
2010 user_rnd_prec
= status
->floatx80_rounding_precision
;
2011 status
->float_rounding_mode
= float_round_nearest_even
;
2012 status
->floatx80_rounding_precision
= 80;
2014 if (compact
< 0x3FFB8000 || compact
> 0x4002FFFF) {
2015 /* |X| >= 16 or |X| < 1/16 */
2016 if (compact
> 0x3FFF8000) { /* |X| >= 16 */
2017 if (compact
> 0x40638000) { /* |X| > 2^(100) */
2018 fp0
= packFloatx80(aSign
, piby2_exp
, pi_sig
);
2019 fp1
= packFloatx80(aSign
, 0x0001, one_sig
);
2021 status
->float_rounding_mode
= user_rnd_mode
;
2022 status
->floatx80_rounding_precision
= user_rnd_prec
;
2024 a
= floatx80_sub(fp0
, fp1
, status
);
2026 float_raise(float_flag_inexact
, status
);
2031 fp1
= packFloatx80(1, one_exp
, one_sig
); /* -1 */
2032 fp1
= floatx80_div(fp1
, fp0
, status
); /* X' = -1/X */
2034 fp0
= floatx80_mul(fp1
, fp1
, status
); /* Y = X'*X' */
2035 fp1
= floatx80_mul(fp0
, fp0
, status
); /* Z = Y*Y */
2036 fp3
= float64_to_floatx80(make_float64(0xBFB70BF398539E6A),
2038 fp2
= float64_to_floatx80(make_float64(0x3FBC7187962D1D7D),
2040 fp3
= floatx80_mul(fp3
, fp1
, status
); /* Z*C5 */
2041 fp2
= floatx80_mul(fp2
, fp1
, status
); /* Z*C4 */
2042 fp3
= floatx80_add(fp3
, float64_to_floatx80(
2043 make_float64(0xBFC24924827107B8), status
),
2044 status
); /* C3+Z*C5 */
2045 fp2
= floatx80_add(fp2
, float64_to_floatx80(
2046 make_float64(0x3FC999999996263E), status
),
2047 status
); /* C2+Z*C4 */
2048 fp1
= floatx80_mul(fp1
, fp3
, status
); /* Z*(C3+Z*C5) */
2049 fp2
= floatx80_mul(fp2
, fp0
, status
); /* Y*(C2+Z*C4) */
2050 fp1
= floatx80_add(fp1
, float64_to_floatx80(
2051 make_float64(0xBFD5555555555536), status
),
2052 status
); /* C1+Z*(C3+Z*C5) */
2053 fp0
= floatx80_mul(fp0
, xsave
, status
); /* X'*Y */
2054 /* [Y*(C2+Z*C4)]+[C1+Z*(C3+Z*C5)] */
2055 fp1
= floatx80_add(fp1
, fp2
, status
);
2056 /* X'*Y*([B1+Z*(B3+Z*B5)]+[Y*(B2+Z*(B4+Z*B6))]) ?? */
2057 fp0
= floatx80_mul(fp0
, fp1
, status
);
2058 fp0
= floatx80_add(fp0
, xsave
, status
);
2059 fp1
= packFloatx80(aSign
, piby2_exp
, pi_sig
);
2061 status
->float_rounding_mode
= user_rnd_mode
;
2062 status
->floatx80_rounding_precision
= user_rnd_prec
;
2064 a
= floatx80_add(fp0
, fp1
, status
);
2066 float_raise(float_flag_inexact
, status
);
2070 } else { /* |X| < 1/16 */
2071 if (compact
< 0x3FD78000) { /* |X| < 2^(-40) */
2072 status
->float_rounding_mode
= user_rnd_mode
;
2073 status
->floatx80_rounding_precision
= user_rnd_prec
;
2075 a
= floatx80_move(a
, status
);
2077 float_raise(float_flag_inexact
, status
);
2083 fp0
= floatx80_mul(fp0
, fp0
, status
); /* Y = X*X */
2084 fp1
= floatx80_mul(fp0
, fp0
, status
); /* Z = Y*Y */
2085 fp2
= float64_to_floatx80(make_float64(0x3FB344447F876989),
2087 fp3
= float64_to_floatx80(make_float64(0xBFB744EE7FAF45DB),
2089 fp2
= floatx80_mul(fp2
, fp1
, status
); /* Z*B6 */
2090 fp3
= floatx80_mul(fp3
, fp1
, status
); /* Z*B5 */
2091 fp2
= floatx80_add(fp2
, float64_to_floatx80(
2092 make_float64(0x3FBC71C646940220), status
),
2093 status
); /* B4+Z*B6 */
2094 fp3
= floatx80_add(fp3
, float64_to_floatx80(
2095 make_float64(0xBFC24924921872F9),
2096 status
), status
); /* B3+Z*B5 */
2097 fp2
= floatx80_mul(fp2
, fp1
, status
); /* Z*(B4+Z*B6) */
2098 fp1
= floatx80_mul(fp1
, fp3
, status
); /* Z*(B3+Z*B5) */
2099 fp2
= floatx80_add(fp2
, float64_to_floatx80(
2100 make_float64(0x3FC9999999998FA9), status
),
2101 status
); /* B2+Z*(B4+Z*B6) */
2102 fp1
= floatx80_add(fp1
, float64_to_floatx80(
2103 make_float64(0xBFD5555555555555), status
),
2104 status
); /* B1+Z*(B3+Z*B5) */
2105 fp2
= floatx80_mul(fp2
, fp0
, status
); /* Y*(B2+Z*(B4+Z*B6)) */
2106 fp0
= floatx80_mul(fp0
, xsave
, status
); /* X*Y */
2107 /* [B1+Z*(B3+Z*B5)]+[Y*(B2+Z*(B4+Z*B6))] */
2108 fp1
= floatx80_add(fp1
, fp2
, status
);
2109 /* X*Y*([B1+Z*(B3+Z*B5)]+[Y*(B2+Z*(B4+Z*B6))]) */
2110 fp0
= floatx80_mul(fp0
, fp1
, status
);
2112 status
->float_rounding_mode
= user_rnd_mode
;
2113 status
->floatx80_rounding_precision
= user_rnd_prec
;
2115 a
= floatx80_add(fp0
, xsave
, status
);
2117 float_raise(float_flag_inexact
, status
);
2123 aSig
&= LIT64(0xF800000000000000);
2124 aSig
|= LIT64(0x0400000000000000);
2125 xsave
= packFloatx80(aSign
, aExp
, aSig
); /* F */
2128 fp2
= packFloatx80(0, one_exp
, one_sig
); /* 1 */
2129 fp1
= floatx80_mul(fp1
, xsave
, status
); /* X*F */
2130 fp0
= floatx80_sub(fp0
, xsave
, status
); /* X-F */
2131 fp1
= floatx80_add(fp1
, fp2
, status
); /* 1 + X*F */
2132 fp0
= floatx80_div(fp0
, fp1
, status
); /* U = (X-F)/(1+X*F) */
2134 tbl_index
= compact
;
2136 tbl_index
&= 0x7FFF0000;
2137 tbl_index
-= 0x3FFB0000;
2139 tbl_index
+= compact
& 0x00007800;
2142 fp3
= atan_tbl
[tbl_index
];
2144 fp3
.high
|= aSign
? 0x8000 : 0; /* ATAN(F) */
2146 fp1
= floatx80_mul(fp0
, fp0
, status
); /* V = U*U */
2147 fp2
= float64_to_floatx80(make_float64(0xBFF6687E314987D8),
2149 fp2
= floatx80_add(fp2
, fp1
, status
); /* A3+V */
2150 fp2
= floatx80_mul(fp2
, fp1
, status
); /* V*(A3+V) */
2151 fp1
= floatx80_mul(fp1
, fp0
, status
); /* U*V */
2152 fp2
= floatx80_add(fp2
, float64_to_floatx80(
2153 make_float64(0x4002AC6934A26DB3), status
),
2154 status
); /* A2+V*(A3+V) */
2155 fp1
= floatx80_mul(fp1
, float64_to_floatx80(
2156 make_float64(0xBFC2476F4E1DA28E), status
),
2157 status
); /* A1+U*V */
2158 fp1
= floatx80_mul(fp1
, fp2
, status
); /* A1*U*V*(A2+V*(A3+V)) */
2159 fp0
= floatx80_add(fp0
, fp1
, status
); /* ATAN(U) */
2161 status
->float_rounding_mode
= user_rnd_mode
;
2162 status
->floatx80_rounding_precision
= user_rnd_prec
;
2164 a
= floatx80_add(fp0
, fp3
, status
); /* ATAN(X) */
2166 float_raise(float_flag_inexact
, status
);
2172 /*----------------------------------------------------------------------------
2174 *----------------------------------------------------------------------------*/
2176 floatx80
floatx80_asin(floatx80 a
, float_status
*status
)
2182 int8_t user_rnd_mode
, user_rnd_prec
;
2185 floatx80 fp0
, fp1
, fp2
, one
;
2187 aSig
= extractFloatx80Frac(a
);
2188 aExp
= extractFloatx80Exp(a
);
2189 aSign
= extractFloatx80Sign(a
);
2191 if (aExp
== 0x7FFF && (uint64_t) (aSig
<< 1)) {
2192 return propagateFloatx80NaNOneArg(a
, status
);
2195 if (aExp
== 0 && aSig
== 0) {
2196 return packFloatx80(aSign
, 0, 0);
2199 compact
= floatx80_make_compact(aExp
, aSig
);
2201 if (compact
>= 0x3FFF8000) { /* |X| >= 1 */
2202 if (aExp
== one_exp
&& aSig
== one_sig
) { /* |X| == 1 */
2203 float_raise(float_flag_inexact
, status
);
2204 a
= packFloatx80(aSign
, piby2_exp
, pi_sig
);
2205 return floatx80_move(a
, status
);
2206 } else { /* |X| > 1 */
2207 float_raise(float_flag_invalid
, status
);
2208 return floatx80_default_nan(status
);
2213 user_rnd_mode
= status
->float_rounding_mode
;
2214 user_rnd_prec
= status
->floatx80_rounding_precision
;
2215 status
->float_rounding_mode
= float_round_nearest_even
;
2216 status
->floatx80_rounding_precision
= 80;
2218 one
= packFloatx80(0, one_exp
, one_sig
);
2221 fp1
= floatx80_sub(one
, fp0
, status
); /* 1 - X */
2222 fp2
= floatx80_add(one
, fp0
, status
); /* 1 + X */
2223 fp1
= floatx80_mul(fp2
, fp1
, status
); /* (1+X)*(1-X) */
2224 fp1
= floatx80_sqrt(fp1
, status
); /* SQRT((1+X)*(1-X)) */
2225 fp0
= floatx80_div(fp0
, fp1
, status
); /* X/SQRT((1+X)*(1-X)) */
2227 status
->float_rounding_mode
= user_rnd_mode
;
2228 status
->floatx80_rounding_precision
= user_rnd_prec
;
2230 a
= floatx80_atan(fp0
, status
); /* ATAN(X/SQRT((1+X)*(1-X))) */
2232 float_raise(float_flag_inexact
, status
);
2237 /*----------------------------------------------------------------------------
2239 *----------------------------------------------------------------------------*/
2241 floatx80
floatx80_acos(floatx80 a
, float_status
*status
)
2247 int8_t user_rnd_mode
, user_rnd_prec
;
2250 floatx80 fp0
, fp1
, one
;
2252 aSig
= extractFloatx80Frac(a
);
2253 aExp
= extractFloatx80Exp(a
);
2254 aSign
= extractFloatx80Sign(a
);
2256 if (aExp
== 0x7FFF && (uint64_t) (aSig
<< 1)) {
2257 return propagateFloatx80NaNOneArg(a
, status
);
2259 if (aExp
== 0 && aSig
== 0) {
2260 float_raise(float_flag_inexact
, status
);
2261 return roundAndPackFloatx80(status
->floatx80_rounding_precision
, 0,
2262 piby2_exp
, pi_sig
, 0, status
);
2265 compact
= floatx80_make_compact(aExp
, aSig
);
2267 if (compact
>= 0x3FFF8000) { /* |X| >= 1 */
2268 if (aExp
== one_exp
&& aSig
== one_sig
) { /* |X| == 1 */
2269 if (aSign
) { /* X == -1 */
2270 a
= packFloatx80(0, pi_exp
, pi_sig
);
2271 float_raise(float_flag_inexact
, status
);
2272 return floatx80_move(a
, status
);
2273 } else { /* X == +1 */
2274 return packFloatx80(0, 0, 0);
2276 } else { /* |X| > 1 */
2277 float_raise(float_flag_invalid
, status
);
2278 return floatx80_default_nan(status
);
2282 user_rnd_mode
= status
->float_rounding_mode
;
2283 user_rnd_prec
= status
->floatx80_rounding_precision
;
2284 status
->float_rounding_mode
= float_round_nearest_even
;
2285 status
->floatx80_rounding_precision
= 80;
2287 one
= packFloatx80(0, one_exp
, one_sig
);
2290 fp1
= floatx80_add(one
, fp0
, status
); /* 1 + X */
2291 fp0
= floatx80_sub(one
, fp0
, status
); /* 1 - X */
2292 fp0
= floatx80_div(fp0
, fp1
, status
); /* (1-X)/(1+X) */
2293 fp0
= floatx80_sqrt(fp0
, status
); /* SQRT((1-X)/(1+X)) */
2294 fp0
= floatx80_atan(fp0
, status
); /* ATAN(SQRT((1-X)/(1+X))) */
2296 status
->float_rounding_mode
= user_rnd_mode
;
2297 status
->floatx80_rounding_precision
= user_rnd_prec
;
2299 a
= floatx80_add(fp0
, fp0
, status
); /* 2 * ATAN(SQRT((1-X)/(1+X))) */
2301 float_raise(float_flag_inexact
, status
);
2306 /*----------------------------------------------------------------------------
2307 | Hyperbolic arc tangent
2308 *----------------------------------------------------------------------------*/
2310 floatx80
floatx80_atanh(floatx80 a
, float_status
*status
)
2316 int8_t user_rnd_mode
, user_rnd_prec
;
2319 floatx80 fp0
, fp1
, fp2
, one
;
2321 aSig
= extractFloatx80Frac(a
);
2322 aExp
= extractFloatx80Exp(a
);
2323 aSign
= extractFloatx80Sign(a
);
2325 if (aExp
== 0x7FFF && (uint64_t) (aSig
<< 1)) {
2326 return propagateFloatx80NaNOneArg(a
, status
);
2329 if (aExp
== 0 && aSig
== 0) {
2330 return packFloatx80(aSign
, 0, 0);
2333 compact
= floatx80_make_compact(aExp
, aSig
);
2335 if (compact
>= 0x3FFF8000) { /* |X| >= 1 */
2336 if (aExp
== one_exp
&& aSig
== one_sig
) { /* |X| == 1 */
2337 float_raise(float_flag_divbyzero
, status
);
2338 return packFloatx80(aSign
, floatx80_infinity
.high
,
2339 floatx80_infinity
.low
);
2340 } else { /* |X| > 1 */
2341 float_raise(float_flag_invalid
, status
);
2342 return floatx80_default_nan(status
);
2346 user_rnd_mode
= status
->float_rounding_mode
;
2347 user_rnd_prec
= status
->floatx80_rounding_precision
;
2348 status
->float_rounding_mode
= float_round_nearest_even
;
2349 status
->floatx80_rounding_precision
= 80;
2351 one
= packFloatx80(0, one_exp
, one_sig
);
2352 fp2
= packFloatx80(aSign
, 0x3FFE, one_sig
); /* SIGN(X) * (1/2) */
2353 fp0
= packFloatx80(0, aExp
, aSig
); /* Y = |X| */
2354 fp1
= packFloatx80(1, aExp
, aSig
); /* -Y */
2355 fp0
= floatx80_add(fp0
, fp0
, status
); /* 2Y */
2356 fp1
= floatx80_add(fp1
, one
, status
); /* 1-Y */
2357 fp0
= floatx80_div(fp0
, fp1
, status
); /* Z = 2Y/(1-Y) */
2358 fp0
= floatx80_lognp1(fp0
, status
); /* LOG1P(Z) */
2360 status
->float_rounding_mode
= user_rnd_mode
;
2361 status
->floatx80_rounding_precision
= user_rnd_prec
;
2363 a
= floatx80_mul(fp0
, fp2
,
2364 status
); /* ATANH(X) = SIGN(X) * (1/2) * LOG1P(Z) */
2366 float_raise(float_flag_inexact
, status
);
2371 /*----------------------------------------------------------------------------
2373 *----------------------------------------------------------------------------*/
2375 floatx80
floatx80_etoxm1(floatx80 a
, float_status
*status
)
2381 int8_t user_rnd_mode
, user_rnd_prec
;
2383 int32_t compact
, n
, j
, m
, m1
;
2384 floatx80 fp0
, fp1
, fp2
, fp3
, l2
, sc
, onebysc
;
2386 aSig
= extractFloatx80Frac(a
);
2387 aExp
= extractFloatx80Exp(a
);
2388 aSign
= extractFloatx80Sign(a
);
2390 if (aExp
== 0x7FFF) {
2391 if ((uint64_t) (aSig
<< 1)) {
2392 return propagateFloatx80NaNOneArg(a
, status
);
2395 return packFloatx80(aSign
, one_exp
, one_sig
);
2397 return packFloatx80(0, floatx80_infinity
.high
,
2398 floatx80_infinity
.low
);
2401 if (aExp
== 0 && aSig
== 0) {
2402 return packFloatx80(aSign
, 0, 0);
2405 user_rnd_mode
= status
->float_rounding_mode
;
2406 user_rnd_prec
= status
->floatx80_rounding_precision
;
2407 status
->float_rounding_mode
= float_round_nearest_even
;
2408 status
->floatx80_rounding_precision
= 80;
2410 if (aExp
>= 0x3FFD) { /* |X| >= 1/4 */
2411 compact
= floatx80_make_compact(aExp
, aSig
);
2413 if (compact
<= 0x4004C215) { /* |X| <= 70 log2 */
2416 fp0
= floatx80_mul(fp0
, float32_to_floatx80(
2417 make_float32(0x42B8AA3B), status
),
2418 status
); /* 64/log2 * X */
2419 n
= floatx80_to_int32(fp0
, status
); /* int(64/log2*X) */
2420 fp0
= int32_to_floatx80(n
, status
);
2422 j
= n
& 0x3F; /* J = N mod 64 */
2423 m
= n
/ 64; /* NOTE: this is really arithmetic right shift by 6 */
2425 /* arithmetic right shift is division and
2426 * round towards minus infinity
2431 /*m += 0x3FFF; // biased exponent of 2^(M) */
2432 /*m1 += 0x3FFF; // biased exponent of -2^(-M) */
2435 fp0
= floatx80_mul(fp0
, float32_to_floatx80(
2436 make_float32(0xBC317218), status
),
2437 status
); /* N * L1, L1 = lead(-log2/64) */
2438 l2
= packFloatx80(0, 0x3FDC, LIT64(0x82E308654361C4C6));
2439 fp2
= floatx80_mul(fp2
, l2
, status
); /* N * L2, L1+L2 = -log2/64 */
2440 fp0
= floatx80_add(fp0
, fp1
, status
); /* X + N*L1 */
2441 fp0
= floatx80_add(fp0
, fp2
, status
); /* R */
2443 fp1
= floatx80_mul(fp0
, fp0
, status
); /* S = R*R */
2444 fp2
= float32_to_floatx80(make_float32(0x3950097B),
2446 fp2
= floatx80_mul(fp2
, fp1
, status
); /* fp2 is S*A6 */
2447 fp3
= floatx80_mul(float32_to_floatx80(make_float32(0x3AB60B6A),
2448 status
), fp1
, status
); /* fp3 is S*A5 */
2449 fp2
= floatx80_add(fp2
, float64_to_floatx80(
2450 make_float64(0x3F81111111174385), status
),
2451 status
); /* fp2 IS A4+S*A6 */
2452 fp3
= floatx80_add(fp3
, float64_to_floatx80(
2453 make_float64(0x3FA5555555554F5A), status
),
2454 status
); /* fp3 is A3+S*A5 */
2455 fp2
= floatx80_mul(fp2
, fp1
, status
); /* fp2 IS S*(A4+S*A6) */
2456 fp3
= floatx80_mul(fp3
, fp1
, status
); /* fp3 IS S*(A3+S*A5) */
2457 fp2
= floatx80_add(fp2
, float64_to_floatx80(
2458 make_float64(0x3FC5555555555555), status
),
2459 status
); /* fp2 IS A2+S*(A4+S*A6) */
2460 fp3
= floatx80_add(fp3
, float32_to_floatx80(
2461 make_float32(0x3F000000), status
),
2462 status
); /* fp3 IS A1+S*(A3+S*A5) */
2463 fp2
= floatx80_mul(fp2
, fp1
,
2464 status
); /* fp2 IS S*(A2+S*(A4+S*A6)) */
2465 fp1
= floatx80_mul(fp1
, fp3
,
2466 status
); /* fp1 IS S*(A1+S*(A3+S*A5)) */
2467 fp2
= floatx80_mul(fp2
, fp0
,
2468 status
); /* fp2 IS R*S*(A2+S*(A4+S*A6)) */
2469 fp0
= floatx80_add(fp0
, fp1
,
2470 status
); /* fp0 IS R+S*(A1+S*(A3+S*A5)) */
2471 fp0
= floatx80_add(fp0
, fp2
, status
); /* fp0 IS EXP(R) - 1 */
2473 fp0
= floatx80_mul(fp0
, exp_tbl
[j
],
2474 status
); /* 2^(J/64)*(Exp(R)-1) */
2477 fp1
= float32_to_floatx80(exp_tbl2
[j
], status
);
2478 onebysc
= packFloatx80(1, m1
+ 0x3FFF, one_sig
); /* -2^(-M) */
2479 fp1
= floatx80_add(fp1
, onebysc
, status
);
2480 fp0
= floatx80_add(fp0
, fp1
, status
);
2481 fp0
= floatx80_add(fp0
, exp_tbl
[j
], status
);
2482 } else if (m
< -3) {
2483 fp0
= floatx80_add(fp0
, float32_to_floatx80(exp_tbl2
[j
],
2485 fp0
= floatx80_add(fp0
, exp_tbl
[j
], status
);
2486 onebysc
= packFloatx80(1, m1
+ 0x3FFF, one_sig
); /* -2^(-M) */
2487 fp0
= floatx80_add(fp0
, onebysc
, status
);
2488 } else { /* -3 <= m <= 63 */
2490 fp0
= floatx80_add(fp0
, float32_to_floatx80(exp_tbl2
[j
],
2492 onebysc
= packFloatx80(1, m1
+ 0x3FFF, one_sig
); /* -2^(-M) */
2493 fp1
= floatx80_add(fp1
, onebysc
, status
);
2494 fp0
= floatx80_add(fp0
, fp1
, status
);
2497 sc
= packFloatx80(0, m
+ 0x3FFF, one_sig
);
2499 status
->float_rounding_mode
= user_rnd_mode
;
2500 status
->floatx80_rounding_precision
= user_rnd_prec
;
2502 a
= floatx80_mul(fp0
, sc
, status
);
2504 float_raise(float_flag_inexact
, status
);
2507 } else { /* |X| > 70 log2 */
2509 fp0
= float32_to_floatx80(make_float32(0xBF800000),
2512 status
->float_rounding_mode
= user_rnd_mode
;
2513 status
->floatx80_rounding_precision
= user_rnd_prec
;
2515 a
= floatx80_add(fp0
, float32_to_floatx80(
2516 make_float32(0x00800000), status
),
2517 status
); /* -1 + 2^(-126) */
2519 float_raise(float_flag_inexact
, status
);
2523 status
->float_rounding_mode
= user_rnd_mode
;
2524 status
->floatx80_rounding_precision
= user_rnd_prec
;
2526 return floatx80_etox(a
, status
);
2529 } else { /* |X| < 1/4 */
2530 if (aExp
>= 0x3FBE) {
2532 fp0
= floatx80_mul(fp0
, fp0
, status
); /* S = X*X */
2533 fp1
= float32_to_floatx80(make_float32(0x2F30CAA8),
2535 fp1
= floatx80_mul(fp1
, fp0
, status
); /* S * B12 */
2536 fp2
= float32_to_floatx80(make_float32(0x310F8290),
2538 fp1
= floatx80_add(fp1
, float32_to_floatx80(
2539 make_float32(0x32D73220), status
),
2541 fp2
= floatx80_mul(fp2
, fp0
, status
);
2542 fp1
= floatx80_mul(fp1
, fp0
, status
);
2543 fp2
= floatx80_add(fp2
, float32_to_floatx80(
2544 make_float32(0x3493F281), status
),
2546 fp1
= floatx80_add(fp1
, float64_to_floatx80(
2547 make_float64(0x3EC71DE3A5774682), status
),
2549 fp2
= floatx80_mul(fp2
, fp0
, status
);
2550 fp1
= floatx80_mul(fp1
, fp0
, status
);
2551 fp2
= floatx80_add(fp2
, float64_to_floatx80(
2552 make_float64(0x3EFA01A019D7CB68), status
),
2554 fp1
= floatx80_add(fp1
, float64_to_floatx80(
2555 make_float64(0x3F2A01A01A019DF3), status
),
2557 fp2
= floatx80_mul(fp2
, fp0
, status
);
2558 fp1
= floatx80_mul(fp1
, fp0
, status
);
2559 fp2
= floatx80_add(fp2
, float64_to_floatx80(
2560 make_float64(0x3F56C16C16C170E2), status
),
2562 fp1
= floatx80_add(fp1
, float64_to_floatx80(
2563 make_float64(0x3F81111111111111), status
),
2565 fp2
= floatx80_mul(fp2
, fp0
, status
);
2566 fp1
= floatx80_mul(fp1
, fp0
, status
);
2567 fp2
= floatx80_add(fp2
, float64_to_floatx80(
2568 make_float64(0x3FA5555555555555), status
),
2570 fp3
= packFloatx80(0, 0x3FFC, LIT64(0xAAAAAAAAAAAAAAAB));
2571 fp1
= floatx80_add(fp1
, fp3
, status
); /* B2 */
2572 fp2
= floatx80_mul(fp2
, fp0
, status
);
2573 fp1
= floatx80_mul(fp1
, fp0
, status
);
2575 fp2
= floatx80_mul(fp2
, fp0
, status
);
2576 fp1
= floatx80_mul(fp1
, a
, status
);
2578 fp0
= floatx80_mul(fp0
, float32_to_floatx80(
2579 make_float32(0x3F000000), status
),
2581 fp1
= floatx80_add(fp1
, fp2
, status
); /* Q */
2582 fp0
= floatx80_add(fp0
, fp1
, status
); /* S*B1+Q */
2584 status
->float_rounding_mode
= user_rnd_mode
;
2585 status
->floatx80_rounding_precision
= user_rnd_prec
;
2587 a
= floatx80_add(fp0
, a
, status
);
2589 float_raise(float_flag_inexact
, status
);
2592 } else { /* |X| < 2^(-65) */
2593 sc
= packFloatx80(1, 1, one_sig
);
2596 if (aExp
< 0x0033) { /* |X| < 2^(-16382) */
2597 fp0
= floatx80_mul(fp0
, float64_to_floatx80(
2598 make_float64(0x48B0000000000000), status
),
2600 fp0
= floatx80_add(fp0
, sc
, status
);
2602 status
->float_rounding_mode
= user_rnd_mode
;
2603 status
->floatx80_rounding_precision
= user_rnd_prec
;
2605 a
= floatx80_mul(fp0
, float64_to_floatx80(
2606 make_float64(0x3730000000000000), status
),
2609 status
->float_rounding_mode
= user_rnd_mode
;
2610 status
->floatx80_rounding_precision
= user_rnd_prec
;
2612 a
= floatx80_add(fp0
, sc
, status
);
2615 float_raise(float_flag_inexact
, status
);
2622 /*----------------------------------------------------------------------------
2623 | Hyperbolic tangent
2624 *----------------------------------------------------------------------------*/
2626 floatx80
floatx80_tanh(floatx80 a
, float_status
*status
)
2630 uint64_t aSig
, vSig
;
2632 int8_t user_rnd_mode
, user_rnd_prec
;
2638 aSig
= extractFloatx80Frac(a
);
2639 aExp
= extractFloatx80Exp(a
);
2640 aSign
= extractFloatx80Sign(a
);
2642 if (aExp
== 0x7FFF) {
2643 if ((uint64_t) (aSig
<< 1)) {
2644 return propagateFloatx80NaNOneArg(a
, status
);
2646 return packFloatx80(aSign
, one_exp
, one_sig
);
2649 if (aExp
== 0 && aSig
== 0) {
2650 return packFloatx80(aSign
, 0, 0);
2653 user_rnd_mode
= status
->float_rounding_mode
;
2654 user_rnd_prec
= status
->floatx80_rounding_precision
;
2655 status
->float_rounding_mode
= float_round_nearest_even
;
2656 status
->floatx80_rounding_precision
= 80;
2658 compact
= floatx80_make_compact(aExp
, aSig
);
2660 if (compact
< 0x3FD78000 || compact
> 0x3FFFDDCE) {
2662 if (compact
< 0x3FFF8000) {
2664 status
->float_rounding_mode
= user_rnd_mode
;
2665 status
->floatx80_rounding_precision
= user_rnd_prec
;
2667 a
= floatx80_move(a
, status
);
2669 float_raise(float_flag_inexact
, status
);
2673 if (compact
> 0x40048AA1) {
2676 sign
|= aSign
? 0x80000000 : 0x00000000;
2677 fp0
= float32_to_floatx80(make_float32(sign
), status
);
2679 sign
^= 0x80800000; /* -SIGN(X)*EPS */
2681 status
->float_rounding_mode
= user_rnd_mode
;
2682 status
->floatx80_rounding_precision
= user_rnd_prec
;
2684 a
= floatx80_add(fp0
, float32_to_floatx80(make_float32(sign
),
2687 float_raise(float_flag_inexact
, status
);
2691 fp0
= packFloatx80(0, aExp
+ 1, aSig
); /* Y = 2|X| */
2692 fp0
= floatx80_etox(fp0
, status
); /* FP0 IS EXP(Y) */
2693 fp0
= floatx80_add(fp0
, float32_to_floatx80(
2694 make_float32(0x3F800000),
2695 status
), status
); /* EXP(Y)+1 */
2696 sign
= aSign
? 0x80000000 : 0x00000000;
2697 fp1
= floatx80_div(float32_to_floatx80(make_float32(
2698 sign
^ 0xC0000000), status
), fp0
,
2699 status
); /* -SIGN(X)*2 / [EXP(Y)+1] */
2700 fp0
= float32_to_floatx80(make_float32(sign
| 0x3F800000),
2703 status
->float_rounding_mode
= user_rnd_mode
;
2704 status
->floatx80_rounding_precision
= user_rnd_prec
;
2706 a
= floatx80_add(fp1
, fp0
, status
);
2708 float_raise(float_flag_inexact
, status
);
2713 } else { /* 2**(-40) < |X| < (5/2)LOG2 */
2714 fp0
= packFloatx80(0, aExp
+ 1, aSig
); /* Y = 2|X| */
2715 fp0
= floatx80_etoxm1(fp0
, status
); /* FP0 IS Z = EXPM1(Y) */
2716 fp1
= floatx80_add(fp0
, float32_to_floatx80(make_float32(0x40000000),
2720 vSign
= extractFloatx80Sign(fp1
);
2721 vExp
= extractFloatx80Exp(fp1
);
2722 vSig
= extractFloatx80Frac(fp1
);
2724 fp1
= packFloatx80(vSign
^ aSign
, vExp
, vSig
);
2726 status
->float_rounding_mode
= user_rnd_mode
;
2727 status
->floatx80_rounding_precision
= user_rnd_prec
;
2729 a
= floatx80_div(fp0
, fp1
, status
);
2731 float_raise(float_flag_inexact
, status
);
2737 /*----------------------------------------------------------------------------
2739 *----------------------------------------------------------------------------*/
2741 floatx80
floatx80_sinh(floatx80 a
, float_status
*status
)
2747 int8_t user_rnd_mode
, user_rnd_prec
;
2750 floatx80 fp0
, fp1
, fp2
;
2753 aSig
= extractFloatx80Frac(a
);
2754 aExp
= extractFloatx80Exp(a
);
2755 aSign
= extractFloatx80Sign(a
);
2757 if (aExp
== 0x7FFF) {
2758 if ((uint64_t) (aSig
<< 1)) {
2759 return propagateFloatx80NaNOneArg(a
, status
);
2761 return packFloatx80(aSign
, floatx80_infinity
.high
,
2762 floatx80_infinity
.low
);
2765 if (aExp
== 0 && aSig
== 0) {
2766 return packFloatx80(aSign
, 0, 0);
2769 user_rnd_mode
= status
->float_rounding_mode
;
2770 user_rnd_prec
= status
->floatx80_rounding_precision
;
2771 status
->float_rounding_mode
= float_round_nearest_even
;
2772 status
->floatx80_rounding_precision
= 80;
2774 compact
= floatx80_make_compact(aExp
, aSig
);
2776 if (compact
> 0x400CB167) {
2778 if (compact
> 0x400CB2B3) {
2779 status
->float_rounding_mode
= user_rnd_mode
;
2780 status
->floatx80_rounding_precision
= user_rnd_prec
;
2782 return roundAndPackFloatx80(status
->floatx80_rounding_precision
,
2783 aSign
, 0x8000, aSig
, 0, status
);
2785 fp0
= floatx80_abs(a
); /* Y = |X| */
2786 fp0
= floatx80_sub(fp0
, float64_to_floatx80(
2787 make_float64(0x40C62D38D3D64634), status
),
2788 status
); /* (|X|-16381LOG2_LEAD) */
2789 fp0
= floatx80_sub(fp0
, float64_to_floatx80(
2790 make_float64(0x3D6F90AEB1E75CC7), status
),
2791 status
); /* |X| - 16381 LOG2, ACCURATE */
2792 fp0
= floatx80_etox(fp0
, status
);
2793 fp2
= packFloatx80(aSign
, 0x7FFB, one_sig
);
2795 status
->float_rounding_mode
= user_rnd_mode
;
2796 status
->floatx80_rounding_precision
= user_rnd_prec
;
2798 a
= floatx80_mul(fp0
, fp2
, status
);
2800 float_raise(float_flag_inexact
, status
);
2804 } else { /* |X| < 16380 LOG2 */
2805 fp0
= floatx80_abs(a
); /* Y = |X| */
2806 fp0
= floatx80_etoxm1(fp0
, status
); /* FP0 IS Z = EXPM1(Y) */
2807 fp1
= floatx80_add(fp0
, float32_to_floatx80(make_float32(0x3F800000),
2808 status
), status
); /* 1+Z */
2810 fp0
= floatx80_div(fp0
, fp1
, status
); /* Z/(1+Z) */
2811 fp0
= floatx80_add(fp0
, fp2
, status
);
2813 fact
= packFloat32(aSign
, 0x7E, 0);
2815 status
->float_rounding_mode
= user_rnd_mode
;
2816 status
->floatx80_rounding_precision
= user_rnd_prec
;
2818 a
= floatx80_mul(fp0
, float32_to_floatx80(fact
, status
), status
);
2820 float_raise(float_flag_inexact
, status
);
2826 /*----------------------------------------------------------------------------
2828 *----------------------------------------------------------------------------*/
2830 floatx80
floatx80_cosh(floatx80 a
, float_status
*status
)
2835 int8_t user_rnd_mode
, user_rnd_prec
;
2840 aSig
= extractFloatx80Frac(a
);
2841 aExp
= extractFloatx80Exp(a
);
2843 if (aExp
== 0x7FFF) {
2844 if ((uint64_t) (aSig
<< 1)) {
2845 return propagateFloatx80NaNOneArg(a
, status
);
2847 return packFloatx80(0, floatx80_infinity
.high
,
2848 floatx80_infinity
.low
);
2851 if (aExp
== 0 && aSig
== 0) {
2852 return packFloatx80(0, one_exp
, one_sig
);
2855 user_rnd_mode
= status
->float_rounding_mode
;
2856 user_rnd_prec
= status
->floatx80_rounding_precision
;
2857 status
->float_rounding_mode
= float_round_nearest_even
;
2858 status
->floatx80_rounding_precision
= 80;
2860 compact
= floatx80_make_compact(aExp
, aSig
);
2862 if (compact
> 0x400CB167) {
2863 if (compact
> 0x400CB2B3) {
2864 status
->float_rounding_mode
= user_rnd_mode
;
2865 status
->floatx80_rounding_precision
= user_rnd_prec
;
2866 return roundAndPackFloatx80(status
->floatx80_rounding_precision
, 0,
2867 0x8000, one_sig
, 0, status
);
2869 fp0
= packFloatx80(0, aExp
, aSig
);
2870 fp0
= floatx80_sub(fp0
, float64_to_floatx80(
2871 make_float64(0x40C62D38D3D64634), status
),
2873 fp0
= floatx80_sub(fp0
, float64_to_floatx80(
2874 make_float64(0x3D6F90AEB1E75CC7), status
),
2876 fp0
= floatx80_etox(fp0
, status
);
2877 fp1
= packFloatx80(0, 0x7FFB, one_sig
);
2879 status
->float_rounding_mode
= user_rnd_mode
;
2880 status
->floatx80_rounding_precision
= user_rnd_prec
;
2882 a
= floatx80_mul(fp0
, fp1
, status
);
2884 float_raise(float_flag_inexact
, status
);
2890 fp0
= packFloatx80(0, aExp
, aSig
); /* |X| */
2891 fp0
= floatx80_etox(fp0
, status
); /* EXP(|X|) */
2892 fp0
= floatx80_mul(fp0
, float32_to_floatx80(make_float32(0x3F000000),
2893 status
), status
); /* (1/2)*EXP(|X|) */
2894 fp1
= float32_to_floatx80(make_float32(0x3E800000), status
); /* 1/4 */
2895 fp1
= floatx80_div(fp1
, fp0
, status
); /* 1/(2*EXP(|X|)) */
2897 status
->float_rounding_mode
= user_rnd_mode
;
2898 status
->floatx80_rounding_precision
= user_rnd_prec
;
2900 a
= floatx80_add(fp0
, fp1
, status
);
2902 float_raise(float_flag_inexact
, status
);