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.
18 * Portions of this work are licensed under the terms of the GNU GPL,
19 * version 2 or later. See the COPYING file in the top-level directory.
22 #include "qemu/osdep.h"
23 #include "softfloat.h"
24 #include "fpu/softfloat-macros.h"
25 #include "softfloat_fpsp_tables.h"
28 #define piby2_exp 0x3FFF
29 #define pi_sig UINT64_C(0xc90fdaa22168c235)
31 static floatx80
propagateFloatx80NaNOneArg(floatx80 a
, float_status
*status
)
33 if (floatx80_is_signaling_nan(a
, status
)) {
34 float_raise(float_flag_invalid
, status
);
35 a
= floatx80_silence_nan(a
, status
);
38 if (status
->default_nan_mode
) {
39 return floatx80_default_nan(status
);
46 * Returns the mantissa of the extended double-precision floating-point
50 floatx80
floatx80_getman(floatx80 a
, float_status
*status
)
56 aSig
= extractFloatx80Frac(a
);
57 aExp
= extractFloatx80Exp(a
);
58 aSign
= extractFloatx80Sign(a
);
61 if ((uint64_t) (aSig
<< 1)) {
62 return propagateFloatx80NaNOneArg(a
, status
);
64 float_raise(float_flag_invalid
, status
);
65 return floatx80_default_nan(status
);
70 return packFloatx80(aSign
, 0, 0);
72 normalizeFloatx80Subnormal(aSig
, &aExp
, &aSig
);
75 return roundAndPackFloatx80(status
->floatx80_rounding_precision
, aSign
,
76 0x3FFF, aSig
, 0, status
);
80 * Returns the exponent of the extended double-precision floating-point
81 * value `a' as an extended double-precision value.
84 floatx80
floatx80_getexp(floatx80 a
, float_status
*status
)
90 aSig
= extractFloatx80Frac(a
);
91 aExp
= extractFloatx80Exp(a
);
92 aSign
= extractFloatx80Sign(a
);
95 if ((uint64_t) (aSig
<< 1)) {
96 return propagateFloatx80NaNOneArg(a
, status
);
98 float_raise(float_flag_invalid
, status
);
99 return floatx80_default_nan(status
);
104 return packFloatx80(aSign
, 0, 0);
106 normalizeFloatx80Subnormal(aSig
, &aExp
, &aSig
);
109 return int32_to_floatx80(aExp
- 0x3FFF, status
);
113 * Scales extended double-precision floating-point value in operand `a' by
114 * value `b'. The function truncates the value in the second operand 'b' to
115 * an integral value and adds that value to the exponent of the operand 'a'.
116 * The operation performed according to the IEC/IEEE Standard for Binary
117 * Floating-Point Arithmetic.
120 floatx80
floatx80_scale(floatx80 a
, floatx80 b
, float_status
*status
)
123 int32_t aExp
, bExp
, shiftCount
;
126 aSig
= extractFloatx80Frac(a
);
127 aExp
= extractFloatx80Exp(a
);
128 aSign
= extractFloatx80Sign(a
);
129 bSig
= extractFloatx80Frac(b
);
130 bExp
= extractFloatx80Exp(b
);
131 bSign
= extractFloatx80Sign(b
);
133 if (bExp
== 0x7FFF) {
134 if ((uint64_t) (bSig
<< 1) ||
135 ((aExp
== 0x7FFF) && (uint64_t) (aSig
<< 1))) {
136 return propagateFloatx80NaN(a
, b
, status
);
138 float_raise(float_flag_invalid
, status
);
139 return floatx80_default_nan(status
);
141 if (aExp
== 0x7FFF) {
142 if ((uint64_t) (aSig
<< 1)) {
143 return propagateFloatx80NaN(a
, b
, status
);
145 return packFloatx80(aSign
, floatx80_infinity
.high
,
146 floatx80_infinity
.low
);
150 return packFloatx80(aSign
, 0, 0);
155 normalizeFloatx80Subnormal(aSig
, &aExp
, &aSig
);
163 aExp
= bSign
? -0x6001 : 0xE000;
164 return roundAndPackFloatx80(status
->floatx80_rounding_precision
,
165 aSign
, aExp
, aSig
, 0, status
);
168 shiftCount
= 0x403E - bExp
;
170 aExp
= bSign
? (aExp
- bSig
) : (aExp
+ bSig
);
172 return roundAndPackFloatx80(status
->floatx80_rounding_precision
,
173 aSign
, aExp
, aSig
, 0, status
);
176 floatx80
floatx80_move(floatx80 a
, float_status
*status
)
182 aSig
= extractFloatx80Frac(a
);
183 aExp
= extractFloatx80Exp(a
);
184 aSign
= extractFloatx80Sign(a
);
186 if (aExp
== 0x7FFF) {
187 if ((uint64_t)(aSig
<< 1)) {
188 return propagateFloatx80NaNOneArg(a
, status
);
196 normalizeRoundAndPackFloatx80(status
->floatx80_rounding_precision
,
197 aSign
, aExp
, aSig
, 0, status
);
199 return roundAndPackFloatx80(status
->floatx80_rounding_precision
, aSign
,
200 aExp
, aSig
, 0, status
);
204 * Algorithms for transcendental functions supported by MC68881 and MC68882
205 * mathematical coprocessors. The functions are derived from FPSP library.
208 #define one_exp 0x3FFF
209 #define one_sig UINT64_C(0x8000000000000000)
212 * Function for compactifying extended double-precision floating point values.
215 static int32_t floatx80_make_compact(int32_t aExp
, uint64_t aSig
)
217 return (aExp
<< 16) | (aSig
>> 48);
221 * Log base e of x plus 1
224 floatx80
floatx80_lognp1(floatx80 a
, float_status
*status
)
230 int8_t user_rnd_mode
, user_rnd_prec
;
232 int32_t compact
, j
, k
;
233 floatx80 fp0
, fp1
, fp2
, fp3
, f
, logof2
, klog2
, saveu
;
235 aSig
= extractFloatx80Frac(a
);
236 aExp
= extractFloatx80Exp(a
);
237 aSign
= extractFloatx80Sign(a
);
239 if (aExp
== 0x7FFF) {
240 if ((uint64_t) (aSig
<< 1)) {
241 propagateFloatx80NaNOneArg(a
, status
);
244 float_raise(float_flag_invalid
, status
);
245 return floatx80_default_nan(status
);
247 return packFloatx80(0, floatx80_infinity
.high
, floatx80_infinity
.low
);
250 if (aExp
== 0 && aSig
== 0) {
251 return packFloatx80(aSign
, 0, 0);
254 if (aSign
&& aExp
>= one_exp
) {
255 if (aExp
== one_exp
&& aSig
== one_sig
) {
256 float_raise(float_flag_divbyzero
, status
);
257 return packFloatx80(aSign
, floatx80_infinity
.high
,
258 floatx80_infinity
.low
);
260 float_raise(float_flag_invalid
, status
);
261 return floatx80_default_nan(status
);
264 if (aExp
< 0x3f99 || (aExp
== 0x3f99 && aSig
== one_sig
)) {
265 /* <= min threshold */
266 float_raise(float_flag_inexact
, status
);
267 return floatx80_move(a
, status
);
270 user_rnd_mode
= status
->float_rounding_mode
;
271 user_rnd_prec
= status
->floatx80_rounding_precision
;
272 status
->float_rounding_mode
= float_round_nearest_even
;
273 status
->floatx80_rounding_precision
= 80;
275 compact
= floatx80_make_compact(aExp
, aSig
);
280 fp0
= floatx80_add(fp0
, float32_to_floatx80(make_float32(0x3F800000),
281 status
), status
); /* X = (1+Z) */
283 aExp
= extractFloatx80Exp(fp0
);
284 aSig
= extractFloatx80Frac(fp0
);
286 compact
= floatx80_make_compact(aExp
, aSig
);
288 if (compact
< 0x3FFE8000 || compact
> 0x3FFFC000) {
289 /* |X| < 1/2 or |X| > 3/2 */
291 fp1
= int32_to_floatx80(k
, status
);
293 fSig
= (aSig
& UINT64_C(0xFE00000000000000)) | UINT64_C(0x0100000000000000);
294 j
= (fSig
>> 56) & 0x7E; /* DISPLACEMENT FOR 1/F */
296 f
= packFloatx80(0, 0x3FFF, fSig
); /* F */
297 fp0
= packFloatx80(0, 0x3FFF, aSig
); /* Y */
299 fp0
= floatx80_sub(fp0
, f
, status
); /* Y-F */
303 fp0
= floatx80_mul(fp0
, log_tbl
[j
], status
); /* FP0 IS U = (Y-F)/F */
304 logof2
= packFloatx80(0, 0x3FFE, UINT64_C(0xB17217F7D1CF79AC));
305 klog2
= floatx80_mul(fp1
, logof2
, status
); /* FP1 IS K*LOG2 */
306 fp2
= floatx80_mul(fp0
, fp0
, status
); /* FP2 IS V=U*U */
311 fp1
= floatx80_mul(fp1
, float64_to_floatx80(
312 make_float64(0x3FC2499AB5E4040B), status
),
314 fp2
= floatx80_mul(fp2
, float64_to_floatx80(
315 make_float64(0xBFC555B5848CB7DB), status
),
317 fp1
= floatx80_add(fp1
, float64_to_floatx80(
318 make_float64(0x3FC99999987D8730), status
),
319 status
); /* A4+V*A6 */
320 fp2
= floatx80_add(fp2
, float64_to_floatx80(
321 make_float64(0xBFCFFFFFFF6F7E97), status
),
322 status
); /* A3+V*A5 */
323 fp1
= floatx80_mul(fp1
, fp3
, status
); /* V*(A4+V*A6) */
324 fp2
= floatx80_mul(fp2
, fp3
, status
); /* V*(A3+V*A5) */
325 fp1
= floatx80_add(fp1
, float64_to_floatx80(
326 make_float64(0x3FD55555555555A4), status
),
327 status
); /* A2+V*(A4+V*A6) */
328 fp2
= floatx80_add(fp2
, float64_to_floatx80(
329 make_float64(0xBFE0000000000008), status
),
330 status
); /* A1+V*(A3+V*A5) */
331 fp1
= floatx80_mul(fp1
, fp3
, status
); /* V*(A2+V*(A4+V*A6)) */
332 fp2
= floatx80_mul(fp2
, fp3
, status
); /* V*(A1+V*(A3+V*A5)) */
333 fp1
= floatx80_mul(fp1
, fp0
, status
); /* U*V*(A2+V*(A4+V*A6)) */
334 fp0
= floatx80_add(fp0
, fp2
, status
); /* U+V*(A1+V*(A3+V*A5)) */
336 fp1
= floatx80_add(fp1
, log_tbl
[j
+ 1],
337 status
); /* LOG(F)+U*V*(A2+V*(A4+V*A6)) */
338 fp0
= floatx80_add(fp0
, fp1
, status
); /* FP0 IS LOG(F) + LOG(1+U) */
340 status
->float_rounding_mode
= user_rnd_mode
;
341 status
->floatx80_rounding_precision
= user_rnd_prec
;
343 a
= floatx80_add(fp0
, klog2
, status
);
345 float_raise(float_flag_inexact
, status
);
348 } else if (compact
< 0x3FFEF07D || compact
> 0x3FFF8841) {
349 /* |X| < 1/16 or |X| > -1/16 */
351 fSig
= (aSig
& UINT64_C(0xFE00000000000000)) | UINT64_C(0x0100000000000000);
352 f
= packFloatx80(0, 0x3FFF, fSig
); /* F */
353 j
= (fSig
>> 56) & 0x7E; /* DISPLACEMENT FOR 1/F */
355 if (compact
>= 0x3FFF8000) { /* 1+Z >= 1 */
357 fp0
= floatx80_sub(float32_to_floatx80(make_float32(0x3F800000),
358 status
), f
, status
); /* 1-F */
359 fp0
= floatx80_add(fp0
, fp1
, status
); /* FP0 IS Y-F = (1-F)+Z */
360 fp1
= packFloatx80(0, 0, 0); /* K = 0 */
363 fp0
= floatx80_sub(float32_to_floatx80(make_float32(0x40000000),
364 status
), f
, status
); /* 2-F */
365 fp1
= floatx80_add(fp1
, fp1
, status
); /* 2Z */
366 fp0
= floatx80_add(fp0
, fp1
, status
); /* FP0 IS Y-F = (2-F)+2Z */
367 fp1
= packFloatx80(1, one_exp
, one_sig
); /* K = -1 */
372 fp1
= floatx80_add(fp1
, fp1
, status
); /* FP1 IS 2Z */
373 fp0
= floatx80_add(fp0
, float32_to_floatx80(make_float32(0x3F800000),
374 status
), status
); /* FP0 IS 1+X */
377 fp1
= floatx80_div(fp1
, fp0
, status
); /* U */
379 fp0
= floatx80_mul(fp1
, fp1
, status
); /* FP0 IS V = U*U */
380 fp1
= floatx80_mul(fp0
, fp0
, status
); /* FP1 IS W = V*V */
382 fp3
= float64_to_floatx80(make_float64(0x3F175496ADD7DAD6),
384 fp2
= float64_to_floatx80(make_float64(0x3F3C71C2FE80C7E0),
386 fp3
= floatx80_mul(fp3
, fp1
, status
); /* W*B5 */
387 fp2
= floatx80_mul(fp2
, fp1
, status
); /* W*B4 */
388 fp3
= floatx80_add(fp3
, float64_to_floatx80(
389 make_float64(0x3F624924928BCCFF), status
),
390 status
); /* B3+W*B5 */
391 fp2
= floatx80_add(fp2
, float64_to_floatx80(
392 make_float64(0x3F899999999995EC), status
),
393 status
); /* B2+W*B4 */
394 fp1
= floatx80_mul(fp1
, fp3
, status
); /* W*(B3+W*B5) */
395 fp2
= floatx80_mul(fp2
, fp0
, status
); /* V*(B2+W*B4) */
396 fp1
= floatx80_add(fp1
, float64_to_floatx80(
397 make_float64(0x3FB5555555555555), status
),
398 status
); /* B1+W*(B3+W*B5) */
400 fp0
= floatx80_mul(fp0
, saveu
, status
); /* FP0 IS U*V */
401 fp1
= floatx80_add(fp1
, fp2
,
402 status
); /* B1+W*(B3+W*B5) + V*(B2+W*B4) */
403 fp0
= floatx80_mul(fp0
, fp1
,
404 status
); /* U*V*([B1+W*(B3+W*B5)] + [V*(B2+W*B4)]) */
406 status
->float_rounding_mode
= user_rnd_mode
;
407 status
->floatx80_rounding_precision
= user_rnd_prec
;
409 a
= floatx80_add(fp0
, saveu
, status
);
411 /*if (!floatx80_is_zero(a)) { */
412 float_raise(float_flag_inexact
, status
);
423 floatx80
floatx80_logn(floatx80 a
, float_status
*status
)
429 int8_t user_rnd_mode
, user_rnd_prec
;
431 int32_t compact
, j
, k
, adjk
;
432 floatx80 fp0
, fp1
, fp2
, fp3
, f
, logof2
, klog2
, saveu
;
434 aSig
= extractFloatx80Frac(a
);
435 aExp
= extractFloatx80Exp(a
);
436 aSign
= extractFloatx80Sign(a
);
438 if (aExp
== 0x7FFF) {
439 if ((uint64_t) (aSig
<< 1)) {
440 propagateFloatx80NaNOneArg(a
, status
);
443 return packFloatx80(0, floatx80_infinity
.high
,
444 floatx80_infinity
.low
);
451 if (aSig
== 0) { /* zero */
452 float_raise(float_flag_divbyzero
, status
);
453 return packFloatx80(1, floatx80_infinity
.high
,
454 floatx80_infinity
.low
);
456 if ((aSig
& one_sig
) == 0) { /* denormal */
457 normalizeFloatx80Subnormal(aSig
, &aExp
, &aSig
);
460 a
= packFloatx80(aSign
, aExp
, aSig
);
465 float_raise(float_flag_invalid
, status
);
466 return floatx80_default_nan(status
);
469 user_rnd_mode
= status
->float_rounding_mode
;
470 user_rnd_prec
= status
->floatx80_rounding_precision
;
471 status
->float_rounding_mode
= float_round_nearest_even
;
472 status
->floatx80_rounding_precision
= 80;
474 compact
= floatx80_make_compact(aExp
, aSig
);
476 if (compact
< 0x3FFEF07D || compact
> 0x3FFF8841) {
477 /* |X| < 15/16 or |X| > 17/16 */
480 fp1
= int32_to_floatx80(k
, status
);
482 fSig
= (aSig
& UINT64_C(0xFE00000000000000)) | UINT64_C(0x0100000000000000);
483 j
= (fSig
>> 56) & 0x7E; /* DISPLACEMENT FOR 1/F */
485 f
= packFloatx80(0, 0x3FFF, fSig
); /* F */
486 fp0
= packFloatx80(0, 0x3FFF, aSig
); /* Y */
488 fp0
= floatx80_sub(fp0
, f
, status
); /* Y-F */
491 fp0
= floatx80_mul(fp0
, log_tbl
[j
], status
); /* FP0 IS U = (Y-F)/F */
492 logof2
= packFloatx80(0, 0x3FFE, UINT64_C(0xB17217F7D1CF79AC));
493 klog2
= floatx80_mul(fp1
, logof2
, status
); /* FP1 IS K*LOG2 */
494 fp2
= floatx80_mul(fp0
, fp0
, status
); /* FP2 IS V=U*U */
499 fp1
= floatx80_mul(fp1
, float64_to_floatx80(
500 make_float64(0x3FC2499AB5E4040B), status
),
502 fp2
= floatx80_mul(fp2
, float64_to_floatx80(
503 make_float64(0xBFC555B5848CB7DB), status
),
505 fp1
= floatx80_add(fp1
, float64_to_floatx80(
506 make_float64(0x3FC99999987D8730), status
),
507 status
); /* A4+V*A6 */
508 fp2
= floatx80_add(fp2
, float64_to_floatx80(
509 make_float64(0xBFCFFFFFFF6F7E97), status
),
510 status
); /* A3+V*A5 */
511 fp1
= floatx80_mul(fp1
, fp3
, status
); /* V*(A4+V*A6) */
512 fp2
= floatx80_mul(fp2
, fp3
, status
); /* V*(A3+V*A5) */
513 fp1
= floatx80_add(fp1
, float64_to_floatx80(
514 make_float64(0x3FD55555555555A4), status
),
515 status
); /* A2+V*(A4+V*A6) */
516 fp2
= floatx80_add(fp2
, float64_to_floatx80(
517 make_float64(0xBFE0000000000008), status
),
518 status
); /* A1+V*(A3+V*A5) */
519 fp1
= floatx80_mul(fp1
, fp3
, status
); /* V*(A2+V*(A4+V*A6)) */
520 fp2
= floatx80_mul(fp2
, fp3
, status
); /* V*(A1+V*(A3+V*A5)) */
521 fp1
= floatx80_mul(fp1
, fp0
, status
); /* U*V*(A2+V*(A4+V*A6)) */
522 fp0
= floatx80_add(fp0
, fp2
, status
); /* U+V*(A1+V*(A3+V*A5)) */
524 fp1
= floatx80_add(fp1
, log_tbl
[j
+ 1],
525 status
); /* LOG(F)+U*V*(A2+V*(A4+V*A6)) */
526 fp0
= floatx80_add(fp0
, fp1
, status
); /* FP0 IS LOG(F) + LOG(1+U) */
528 status
->float_rounding_mode
= user_rnd_mode
;
529 status
->floatx80_rounding_precision
= user_rnd_prec
;
531 a
= floatx80_add(fp0
, klog2
, status
);
533 float_raise(float_flag_inexact
, status
);
536 } else { /* |X-1| >= 1/16 */
539 fp1
= floatx80_sub(fp1
, float32_to_floatx80(make_float32(0x3F800000),
540 status
), status
); /* FP1 IS X-1 */
541 fp0
= floatx80_add(fp0
, float32_to_floatx80(make_float32(0x3F800000),
542 status
), status
); /* FP0 IS X+1 */
543 fp1
= floatx80_add(fp1
, fp1
, status
); /* FP1 IS 2(X-1) */
546 fp1
= floatx80_div(fp1
, fp0
, status
); /* U */
548 fp0
= floatx80_mul(fp1
, fp1
, status
); /* FP0 IS V = U*U */
549 fp1
= floatx80_mul(fp0
, fp0
, status
); /* FP1 IS W = V*V */
551 fp3
= float64_to_floatx80(make_float64(0x3F175496ADD7DAD6),
553 fp2
= float64_to_floatx80(make_float64(0x3F3C71C2FE80C7E0),
555 fp3
= floatx80_mul(fp3
, fp1
, status
); /* W*B5 */
556 fp2
= floatx80_mul(fp2
, fp1
, status
); /* W*B4 */
557 fp3
= floatx80_add(fp3
, float64_to_floatx80(
558 make_float64(0x3F624924928BCCFF), status
),
559 status
); /* B3+W*B5 */
560 fp2
= floatx80_add(fp2
, float64_to_floatx80(
561 make_float64(0x3F899999999995EC), status
),
562 status
); /* B2+W*B4 */
563 fp1
= floatx80_mul(fp1
, fp3
, status
); /* W*(B3+W*B5) */
564 fp2
= floatx80_mul(fp2
, fp0
, status
); /* V*(B2+W*B4) */
565 fp1
= floatx80_add(fp1
, float64_to_floatx80(
566 make_float64(0x3FB5555555555555), status
),
567 status
); /* B1+W*(B3+W*B5) */
569 fp0
= floatx80_mul(fp0
, saveu
, status
); /* FP0 IS U*V */
570 fp1
= floatx80_add(fp1
, fp2
, status
); /* B1+W*(B3+W*B5) + V*(B2+W*B4) */
571 fp0
= floatx80_mul(fp0
, fp1
,
572 status
); /* U*V*([B1+W*(B3+W*B5)] + [V*(B2+W*B4)]) */
574 status
->float_rounding_mode
= user_rnd_mode
;
575 status
->floatx80_rounding_precision
= user_rnd_prec
;
577 a
= floatx80_add(fp0
, saveu
, status
);
579 /*if (!floatx80_is_zero(a)) { */
580 float_raise(float_flag_inexact
, status
);
591 floatx80
floatx80_log10(floatx80 a
, float_status
*status
)
597 int8_t user_rnd_mode
, user_rnd_prec
;
601 aSig
= extractFloatx80Frac(a
);
602 aExp
= extractFloatx80Exp(a
);
603 aSign
= extractFloatx80Sign(a
);
605 if (aExp
== 0x7FFF) {
606 if ((uint64_t) (aSig
<< 1)) {
607 propagateFloatx80NaNOneArg(a
, status
);
610 return packFloatx80(0, floatx80_infinity
.high
,
611 floatx80_infinity
.low
);
615 if (aExp
== 0 && aSig
== 0) {
616 float_raise(float_flag_divbyzero
, status
);
617 return packFloatx80(1, floatx80_infinity
.high
,
618 floatx80_infinity
.low
);
622 float_raise(float_flag_invalid
, status
);
623 return floatx80_default_nan(status
);
626 user_rnd_mode
= status
->float_rounding_mode
;
627 user_rnd_prec
= status
->floatx80_rounding_precision
;
628 status
->float_rounding_mode
= float_round_nearest_even
;
629 status
->floatx80_rounding_precision
= 80;
631 fp0
= floatx80_logn(a
, status
);
632 fp1
= packFloatx80(0, 0x3FFD, UINT64_C(0xDE5BD8A937287195)); /* INV_L10 */
634 status
->float_rounding_mode
= user_rnd_mode
;
635 status
->floatx80_rounding_precision
= user_rnd_prec
;
637 a
= floatx80_mul(fp0
, fp1
, status
); /* LOGN(X)*INV_L10 */
639 float_raise(float_flag_inexact
, status
);
648 floatx80
floatx80_log2(floatx80 a
, float_status
*status
)
654 int8_t user_rnd_mode
, user_rnd_prec
;
658 aSig
= extractFloatx80Frac(a
);
659 aExp
= extractFloatx80Exp(a
);
660 aSign
= extractFloatx80Sign(a
);
662 if (aExp
== 0x7FFF) {
663 if ((uint64_t) (aSig
<< 1)) {
664 propagateFloatx80NaNOneArg(a
, status
);
667 return packFloatx80(0, floatx80_infinity
.high
,
668 floatx80_infinity
.low
);
674 float_raise(float_flag_divbyzero
, status
);
675 return packFloatx80(1, floatx80_infinity
.high
,
676 floatx80_infinity
.low
);
678 normalizeFloatx80Subnormal(aSig
, &aExp
, &aSig
);
682 float_raise(float_flag_invalid
, status
);
683 return floatx80_default_nan(status
);
686 user_rnd_mode
= status
->float_rounding_mode
;
687 user_rnd_prec
= status
->floatx80_rounding_precision
;
688 status
->float_rounding_mode
= float_round_nearest_even
;
689 status
->floatx80_rounding_precision
= 80;
691 if (aSig
== one_sig
) { /* X is 2^k */
692 status
->float_rounding_mode
= user_rnd_mode
;
693 status
->floatx80_rounding_precision
= user_rnd_prec
;
695 a
= int32_to_floatx80(aExp
- 0x3FFF, status
);
697 fp0
= floatx80_logn(a
, status
);
698 fp1
= packFloatx80(0, 0x3FFF, UINT64_C(0xB8AA3B295C17F0BC)); /* INV_L2 */
700 status
->float_rounding_mode
= user_rnd_mode
;
701 status
->floatx80_rounding_precision
= user_rnd_prec
;
703 a
= floatx80_mul(fp0
, fp1
, status
); /* LOGN(X)*INV_L2 */
706 float_raise(float_flag_inexact
, status
);
715 floatx80
floatx80_etox(floatx80 a
, float_status
*status
)
721 int8_t user_rnd_mode
, user_rnd_prec
;
723 int32_t compact
, n
, j
, k
, m
, m1
;
724 floatx80 fp0
, fp1
, fp2
, fp3
, l2
, scale
, adjscale
;
727 aSig
= extractFloatx80Frac(a
);
728 aExp
= extractFloatx80Exp(a
);
729 aSign
= extractFloatx80Sign(a
);
731 if (aExp
== 0x7FFF) {
732 if ((uint64_t) (aSig
<< 1)) {
733 return propagateFloatx80NaNOneArg(a
, status
);
736 return packFloatx80(0, 0, 0);
738 return packFloatx80(0, floatx80_infinity
.high
,
739 floatx80_infinity
.low
);
742 if (aExp
== 0 && aSig
== 0) {
743 return packFloatx80(0, one_exp
, one_sig
);
746 user_rnd_mode
= status
->float_rounding_mode
;
747 user_rnd_prec
= status
->floatx80_rounding_precision
;
748 status
->float_rounding_mode
= float_round_nearest_even
;
749 status
->floatx80_rounding_precision
= 80;
753 if (aExp
>= 0x3FBE) { /* |X| >= 2^(-65) */
754 compact
= floatx80_make_compact(aExp
, aSig
);
756 if (compact
< 0x400CB167) { /* |X| < 16380 log2 */
759 fp0
= floatx80_mul(fp0
, float32_to_floatx80(
760 make_float32(0x42B8AA3B), status
),
761 status
); /* 64/log2 * X */
763 n
= floatx80_to_int32(fp0
, status
); /* int(64/log2*X) */
764 fp0
= int32_to_floatx80(n
, status
);
766 j
= n
& 0x3F; /* J = N mod 64 */
767 m
= n
/ 64; /* NOTE: this is really arithmetic right shift by 6 */
770 * arithmetic right shift is division and
771 * round towards minus infinity
775 m
+= 0x3FFF; /* biased exponent of 2^(M) */
779 fp0
= floatx80_mul(fp0
, float32_to_floatx80(
780 make_float32(0xBC317218), status
),
781 status
); /* N * L1, L1 = lead(-log2/64) */
782 l2
= packFloatx80(0, 0x3FDC, UINT64_C(0x82E308654361C4C6));
783 fp2
= floatx80_mul(fp2
, l2
, status
); /* N * L2, L1+L2 = -log2/64 */
784 fp0
= floatx80_add(fp0
, fp1
, status
); /* X + N*L1 */
785 fp0
= floatx80_add(fp0
, fp2
, status
); /* R */
787 fp1
= floatx80_mul(fp0
, fp0
, status
); /* S = R*R */
788 fp2
= float32_to_floatx80(make_float32(0x3AB60B70),
790 fp2
= floatx80_mul(fp2
, fp1
, status
); /* fp2 is S*A5 */
791 fp3
= floatx80_mul(float32_to_floatx80(make_float32(0x3C088895),
793 status
); /* fp3 is S*A4 */
794 fp2
= floatx80_add(fp2
, float64_to_floatx80(make_float64(
795 0x3FA5555555554431), status
),
796 status
); /* fp2 is A3+S*A5 */
797 fp3
= floatx80_add(fp3
, float64_to_floatx80(make_float64(
798 0x3FC5555555554018), status
),
799 status
); /* fp3 is A2+S*A4 */
800 fp2
= floatx80_mul(fp2
, fp1
, status
); /* fp2 is S*(A3+S*A5) */
801 fp3
= floatx80_mul(fp3
, fp1
, status
); /* fp3 is S*(A2+S*A4) */
802 fp2
= floatx80_add(fp2
, float32_to_floatx80(
803 make_float32(0x3F000000), status
),
804 status
); /* fp2 is A1+S*(A3+S*A5) */
805 fp3
= floatx80_mul(fp3
, fp0
, status
); /* fp3 IS R*S*(A2+S*A4) */
806 fp2
= floatx80_mul(fp2
, fp1
,
807 status
); /* fp2 IS S*(A1+S*(A3+S*A5)) */
808 fp0
= floatx80_add(fp0
, fp3
, status
); /* fp0 IS R+R*S*(A2+S*A4) */
809 fp0
= floatx80_add(fp0
, fp2
, status
); /* fp0 IS EXP(R) - 1 */
812 fp0
= floatx80_mul(fp0
, fp1
, status
); /* 2^(J/64)*(Exp(R)-1) */
813 fp0
= floatx80_add(fp0
, float32_to_floatx80(exp_tbl2
[j
], status
),
814 status
); /* accurate 2^(J/64) */
815 fp0
= floatx80_add(fp0
, fp1
,
816 status
); /* 2^(J/64) + 2^(J/64)*(Exp(R)-1) */
818 scale
= packFloatx80(0, m
, one_sig
);
820 adjscale
= packFloatx80(0, m1
, one_sig
);
821 fp0
= floatx80_mul(fp0
, adjscale
, status
);
824 status
->float_rounding_mode
= user_rnd_mode
;
825 status
->floatx80_rounding_precision
= user_rnd_prec
;
827 a
= floatx80_mul(fp0
, scale
, status
);
829 float_raise(float_flag_inexact
, status
);
832 } else { /* |X| >= 16380 log2 */
833 if (compact
> 0x400CB27C) { /* |X| >= 16480 log2 */
834 status
->float_rounding_mode
= user_rnd_mode
;
835 status
->floatx80_rounding_precision
= user_rnd_prec
;
837 a
= roundAndPackFloatx80(
838 status
->floatx80_rounding_precision
,
839 0, -0x1000, aSig
, 0, status
);
841 a
= roundAndPackFloatx80(
842 status
->floatx80_rounding_precision
,
843 0, 0x8000, aSig
, 0, status
);
845 float_raise(float_flag_inexact
, status
);
851 fp0
= floatx80_mul(fp0
, float32_to_floatx80(
852 make_float32(0x42B8AA3B), status
),
853 status
); /* 64/log2 * X */
855 n
= floatx80_to_int32(fp0
, status
); /* int(64/log2*X) */
856 fp0
= int32_to_floatx80(n
, status
);
858 j
= n
& 0x3F; /* J = N mod 64 */
859 /* NOTE: this is really arithmetic right shift by 6 */
862 /* arithmetic right shift is division and
863 * round towards minus infinity
867 /* NOTE: this is really arithmetic right shift by 1 */
869 if (k
< 0 && (k
& 1)) {
870 /* arithmetic right shift is division and
871 * round towards minus infinity
876 m1
+= 0x3FFF; /* biased exponent of 2^(M1) */
877 m
+= 0x3FFF; /* biased exponent of 2^(M) */
882 } else { /* |X| < 2^(-65) */
883 status
->float_rounding_mode
= user_rnd_mode
;
884 status
->floatx80_rounding_precision
= user_rnd_prec
;
886 a
= floatx80_add(a
, float32_to_floatx80(make_float32(0x3F800000),
887 status
), status
); /* 1 + X */
889 float_raise(float_flag_inexact
, status
);
899 floatx80
floatx80_twotox(floatx80 a
, float_status
*status
)
905 int8_t user_rnd_mode
, user_rnd_prec
;
907 int32_t compact
, n
, j
, l
, m
, m1
;
908 floatx80 fp0
, fp1
, fp2
, fp3
, adjfact
, fact1
, fact2
;
910 aSig
= extractFloatx80Frac(a
);
911 aExp
= extractFloatx80Exp(a
);
912 aSign
= extractFloatx80Sign(a
);
914 if (aExp
== 0x7FFF) {
915 if ((uint64_t) (aSig
<< 1)) {
916 return propagateFloatx80NaNOneArg(a
, status
);
919 return packFloatx80(0, 0, 0);
921 return packFloatx80(0, floatx80_infinity
.high
,
922 floatx80_infinity
.low
);
925 if (aExp
== 0 && aSig
== 0) {
926 return packFloatx80(0, one_exp
, one_sig
);
929 user_rnd_mode
= status
->float_rounding_mode
;
930 user_rnd_prec
= status
->floatx80_rounding_precision
;
931 status
->float_rounding_mode
= float_round_nearest_even
;
932 status
->floatx80_rounding_precision
= 80;
936 compact
= floatx80_make_compact(aExp
, aSig
);
938 if (compact
< 0x3FB98000 || compact
> 0x400D80C0) {
939 /* |X| > 16480 or |X| < 2^(-70) */
940 if (compact
> 0x3FFF8000) { /* |X| > 16480 */
941 status
->float_rounding_mode
= user_rnd_mode
;
942 status
->floatx80_rounding_precision
= user_rnd_prec
;
945 return roundAndPackFloatx80(status
->floatx80_rounding_precision
,
946 0, -0x1000, aSig
, 0, status
);
948 return roundAndPackFloatx80(status
->floatx80_rounding_precision
,
949 0, 0x8000, aSig
, 0, status
);
951 } else { /* |X| < 2^(-70) */
952 status
->float_rounding_mode
= user_rnd_mode
;
953 status
->floatx80_rounding_precision
= user_rnd_prec
;
955 a
= floatx80_add(fp0
, float32_to_floatx80(
956 make_float32(0x3F800000), status
),
959 float_raise(float_flag_inexact
, status
);
963 } else { /* 2^(-70) <= |X| <= 16480 */
965 fp1
= floatx80_mul(fp1
, float32_to_floatx80(
966 make_float32(0x42800000), status
),
967 status
); /* X * 64 */
968 n
= floatx80_to_int32(fp1
, status
);
969 fp1
= int32_to_floatx80(n
, status
);
971 l
= n
/ 64; /* NOTE: this is really arithmetic right shift by 6 */
974 * arithmetic right shift is division and
975 * round towards minus infinity
979 m
= l
/ 2; /* NOTE: this is really arithmetic right shift by 1 */
980 if (l
< 0 && (l
& 1)) {
982 * arithmetic right shift is division and
983 * round towards minus infinity
988 m1
+= 0x3FFF; /* ADJFACT IS 2^(M') */
990 adjfact
= packFloatx80(0, m1
, one_sig
);
993 fact2
.high
= exp2_tbl2
[j
] >> 16;
995 fact2
.low
= (uint64_t)(exp2_tbl2
[j
] & 0xFFFF);
998 fp1
= floatx80_mul(fp1
, float32_to_floatx80(
999 make_float32(0x3C800000), status
),
1000 status
); /* (1/64)*N */
1001 fp0
= floatx80_sub(fp0
, fp1
, status
); /* X - (1/64)*INT(64 X) */
1002 fp2
= packFloatx80(0, 0x3FFE, UINT64_C(0xB17217F7D1CF79AC)); /* LOG2 */
1003 fp0
= floatx80_mul(fp0
, fp2
, status
); /* R */
1006 fp1
= floatx80_mul(fp0
, fp0
, status
); /* S = R*R */
1007 fp2
= float64_to_floatx80(make_float64(0x3F56C16D6F7BD0B2),
1009 fp3
= float64_to_floatx80(make_float64(0x3F811112302C712C),
1011 fp2
= floatx80_mul(fp2
, fp1
, status
); /* S*A5 */
1012 fp3
= floatx80_mul(fp3
, fp1
, status
); /* S*A4 */
1013 fp2
= floatx80_add(fp2
, float64_to_floatx80(
1014 make_float64(0x3FA5555555554CC1), status
),
1015 status
); /* A3+S*A5 */
1016 fp3
= floatx80_add(fp3
, float64_to_floatx80(
1017 make_float64(0x3FC5555555554A54), status
),
1018 status
); /* A2+S*A4 */
1019 fp2
= floatx80_mul(fp2
, fp1
, status
); /* S*(A3+S*A5) */
1020 fp3
= floatx80_mul(fp3
, fp1
, status
); /* S*(A2+S*A4) */
1021 fp2
= floatx80_add(fp2
, float64_to_floatx80(
1022 make_float64(0x3FE0000000000000), status
),
1023 status
); /* A1+S*(A3+S*A5) */
1024 fp3
= floatx80_mul(fp3
, fp0
, status
); /* R*S*(A2+S*A4) */
1026 fp2
= floatx80_mul(fp2
, fp1
, status
); /* S*(A1+S*(A3+S*A5)) */
1027 fp0
= floatx80_add(fp0
, fp3
, status
); /* R+R*S*(A2+S*A4) */
1028 fp0
= floatx80_add(fp0
, fp2
, status
); /* EXP(R) - 1 */
1030 fp0
= floatx80_mul(fp0
, fact1
, status
);
1031 fp0
= floatx80_add(fp0
, fact2
, status
);
1032 fp0
= floatx80_add(fp0
, fact1
, status
);
1034 status
->float_rounding_mode
= user_rnd_mode
;
1035 status
->floatx80_rounding_precision
= user_rnd_prec
;
1037 a
= floatx80_mul(fp0
, adjfact
, status
);
1039 float_raise(float_flag_inexact
, status
);
1049 floatx80
floatx80_tentox(floatx80 a
, float_status
*status
)
1055 int8_t user_rnd_mode
, user_rnd_prec
;
1057 int32_t compact
, n
, j
, l
, m
, m1
;
1058 floatx80 fp0
, fp1
, fp2
, fp3
, adjfact
, fact1
, fact2
;
1060 aSig
= extractFloatx80Frac(a
);
1061 aExp
= extractFloatx80Exp(a
);
1062 aSign
= extractFloatx80Sign(a
);
1064 if (aExp
== 0x7FFF) {
1065 if ((uint64_t) (aSig
<< 1)) {
1066 return propagateFloatx80NaNOneArg(a
, status
);
1069 return packFloatx80(0, 0, 0);
1071 return packFloatx80(0, floatx80_infinity
.high
,
1072 floatx80_infinity
.low
);
1075 if (aExp
== 0 && aSig
== 0) {
1076 return packFloatx80(0, one_exp
, one_sig
);
1079 user_rnd_mode
= status
->float_rounding_mode
;
1080 user_rnd_prec
= status
->floatx80_rounding_precision
;
1081 status
->float_rounding_mode
= float_round_nearest_even
;
1082 status
->floatx80_rounding_precision
= 80;
1086 compact
= floatx80_make_compact(aExp
, aSig
);
1088 if (compact
< 0x3FB98000 || compact
> 0x400B9B07) {
1089 /* |X| > 16480 LOG2/LOG10 or |X| < 2^(-70) */
1090 if (compact
> 0x3FFF8000) { /* |X| > 16480 */
1091 status
->float_rounding_mode
= user_rnd_mode
;
1092 status
->floatx80_rounding_precision
= user_rnd_prec
;
1095 return roundAndPackFloatx80(status
->floatx80_rounding_precision
,
1096 0, -0x1000, aSig
, 0, status
);
1098 return roundAndPackFloatx80(status
->floatx80_rounding_precision
,
1099 0, 0x8000, aSig
, 0, status
);
1101 } else { /* |X| < 2^(-70) */
1102 status
->float_rounding_mode
= user_rnd_mode
;
1103 status
->floatx80_rounding_precision
= user_rnd_prec
;
1105 a
= floatx80_add(fp0
, float32_to_floatx80(
1106 make_float32(0x3F800000), status
),
1107 status
); /* 1 + X */
1109 float_raise(float_flag_inexact
, status
);
1113 } else { /* 2^(-70) <= |X| <= 16480 LOG 2 / LOG 10 */
1115 fp1
= floatx80_mul(fp1
, float64_to_floatx80(
1116 make_float64(0x406A934F0979A371),
1117 status
), status
); /* X*64*LOG10/LOG2 */
1118 n
= floatx80_to_int32(fp1
, status
); /* N=INT(X*64*LOG10/LOG2) */
1119 fp1
= int32_to_floatx80(n
, status
);
1122 l
= n
/ 64; /* NOTE: this is really arithmetic right shift by 6 */
1125 * arithmetic right shift is division and
1126 * round towards minus infinity
1130 m
= l
/ 2; /* NOTE: this is really arithmetic right shift by 1 */
1131 if (l
< 0 && (l
& 1)) {
1133 * arithmetic right shift is division and
1134 * round towards minus infinity
1139 m1
+= 0x3FFF; /* ADJFACT IS 2^(M') */
1141 adjfact
= packFloatx80(0, m1
, one_sig
);
1142 fact1
= exp2_tbl
[j
];
1144 fact2
.high
= exp2_tbl2
[j
] >> 16;
1146 fact2
.low
= (uint64_t)(exp2_tbl2
[j
] & 0xFFFF);
1150 fp1
= floatx80_mul(fp1
, float64_to_floatx80(
1151 make_float64(0x3F734413509F8000), status
),
1152 status
); /* N*(LOG2/64LOG10)_LEAD */
1153 fp3
= packFloatx80(1, 0x3FCD, UINT64_C(0xC0219DC1DA994FD2));
1154 fp2
= floatx80_mul(fp2
, fp3
, status
); /* N*(LOG2/64LOG10)_TRAIL */
1155 fp0
= floatx80_sub(fp0
, fp1
, status
); /* X - N L_LEAD */
1156 fp0
= floatx80_sub(fp0
, fp2
, status
); /* X - N L_TRAIL */
1157 fp2
= packFloatx80(0, 0x4000, UINT64_C(0x935D8DDDAAA8AC17)); /* LOG10 */
1158 fp0
= floatx80_mul(fp0
, fp2
, status
); /* R */
1161 fp1
= floatx80_mul(fp0
, fp0
, status
); /* S = R*R */
1162 fp2
= float64_to_floatx80(make_float64(0x3F56C16D6F7BD0B2),
1164 fp3
= float64_to_floatx80(make_float64(0x3F811112302C712C),
1166 fp2
= floatx80_mul(fp2
, fp1
, status
); /* S*A5 */
1167 fp3
= floatx80_mul(fp3
, fp1
, status
); /* S*A4 */
1168 fp2
= floatx80_add(fp2
, float64_to_floatx80(
1169 make_float64(0x3FA5555555554CC1), status
),
1170 status
); /* A3+S*A5 */
1171 fp3
= floatx80_add(fp3
, float64_to_floatx80(
1172 make_float64(0x3FC5555555554A54), status
),
1173 status
); /* A2+S*A4 */
1174 fp2
= floatx80_mul(fp2
, fp1
, status
); /* S*(A3+S*A5) */
1175 fp3
= floatx80_mul(fp3
, fp1
, status
); /* S*(A2+S*A4) */
1176 fp2
= floatx80_add(fp2
, float64_to_floatx80(
1177 make_float64(0x3FE0000000000000), status
),
1178 status
); /* A1+S*(A3+S*A5) */
1179 fp3
= floatx80_mul(fp3
, fp0
, status
); /* R*S*(A2+S*A4) */
1181 fp2
= floatx80_mul(fp2
, fp1
, status
); /* S*(A1+S*(A3+S*A5)) */
1182 fp0
= floatx80_add(fp0
, fp3
, status
); /* R+R*S*(A2+S*A4) */
1183 fp0
= floatx80_add(fp0
, fp2
, status
); /* EXP(R) - 1 */
1185 fp0
= floatx80_mul(fp0
, fact1
, status
);
1186 fp0
= floatx80_add(fp0
, fact2
, status
);
1187 fp0
= floatx80_add(fp0
, fact1
, status
);
1189 status
->float_rounding_mode
= user_rnd_mode
;
1190 status
->floatx80_rounding_precision
= user_rnd_prec
;
1192 a
= floatx80_mul(fp0
, adjfact
, status
);
1194 float_raise(float_flag_inexact
, status
);
1204 floatx80
floatx80_tan(floatx80 a
, float_status
*status
)
1208 uint64_t aSig
, xSig
;
1210 int8_t user_rnd_mode
, user_rnd_prec
;
1212 int32_t compact
, l
, n
, j
;
1213 floatx80 fp0
, fp1
, fp2
, fp3
, fp4
, fp5
, invtwopi
, twopi1
, twopi2
;
1217 aSig
= extractFloatx80Frac(a
);
1218 aExp
= extractFloatx80Exp(a
);
1219 aSign
= extractFloatx80Sign(a
);
1221 if (aExp
== 0x7FFF) {
1222 if ((uint64_t) (aSig
<< 1)) {
1223 return propagateFloatx80NaNOneArg(a
, status
);
1225 float_raise(float_flag_invalid
, status
);
1226 return floatx80_default_nan(status
);
1229 if (aExp
== 0 && aSig
== 0) {
1230 return packFloatx80(aSign
, 0, 0);
1233 user_rnd_mode
= status
->float_rounding_mode
;
1234 user_rnd_prec
= status
->floatx80_rounding_precision
;
1235 status
->float_rounding_mode
= float_round_nearest_even
;
1236 status
->floatx80_rounding_precision
= 80;
1238 compact
= floatx80_make_compact(aExp
, aSig
);
1242 if (compact
< 0x3FD78000 || compact
> 0x4004BC7E) {
1243 /* 2^(-40) > |X| > 15 PI */
1244 if (compact
> 0x3FFF8000) { /* |X| >= 15 PI */
1246 fp1
= packFloatx80(0, 0, 0);
1247 if (compact
== 0x7FFEFFFF) {
1248 twopi1
= packFloatx80(aSign
^ 1, 0x7FFE,
1249 UINT64_C(0xC90FDAA200000000));
1250 twopi2
= packFloatx80(aSign
^ 1, 0x7FDC,
1251 UINT64_C(0x85A308D300000000));
1252 fp0
= floatx80_add(fp0
, twopi1
, status
);
1254 fp0
= floatx80_add(fp0
, twopi2
, status
);
1255 fp1
= floatx80_sub(fp1
, fp0
, status
);
1256 fp1
= floatx80_add(fp1
, twopi2
, status
);
1259 xSign
= extractFloatx80Sign(fp0
);
1260 xExp
= extractFloatx80Exp(fp0
);
1269 invtwopi
= packFloatx80(0, 0x3FFE - l
,
1270 UINT64_C(0xA2F9836E4E44152A)); /* INVTWOPI */
1271 twopi1
= packFloatx80(0, 0x3FFF + l
, UINT64_C(0xC90FDAA200000000));
1272 twopi2
= packFloatx80(0, 0x3FDD + l
, UINT64_C(0x85A308D300000000));
1274 /* SIGN(INARG)*2^63 IN SGL */
1275 twoto63
= packFloat32(xSign
, 0xBE, 0);
1277 fp2
= floatx80_mul(fp0
, invtwopi
, status
);
1278 fp2
= floatx80_add(fp2
, float32_to_floatx80(twoto63
, status
),
1279 status
); /* THE FRACT PART OF FP2 IS ROUNDED */
1280 fp2
= floatx80_sub(fp2
, float32_to_floatx80(twoto63
, status
),
1281 status
); /* FP2 is N */
1282 fp4
= floatx80_mul(twopi1
, fp2
, status
); /* W = N*P1 */
1283 fp5
= floatx80_mul(twopi2
, fp2
, status
); /* w = N*P2 */
1284 fp3
= floatx80_add(fp4
, fp5
, status
); /* FP3 is P */
1285 fp4
= floatx80_sub(fp4
, fp3
, status
); /* W-P */
1286 fp0
= floatx80_sub(fp0
, fp3
, status
); /* FP0 is A := R - P */
1287 fp4
= floatx80_add(fp4
, fp5
, status
); /* FP4 is p = (W-P)+w */
1288 fp3
= fp0
; /* FP3 is A */
1289 fp1
= floatx80_sub(fp1
, fp4
, status
); /* FP1 is a := r - p */
1290 fp0
= floatx80_add(fp0
, fp1
, status
); /* FP0 is R := A+a */
1293 n
= floatx80_to_int32(fp2
, status
);
1296 fp3
= floatx80_sub(fp3
, fp0
, status
); /* A-R */
1297 fp1
= floatx80_add(fp1
, fp3
, status
); /* FP1 is r := (A-R)+a */
1300 status
->float_rounding_mode
= user_rnd_mode
;
1301 status
->floatx80_rounding_precision
= user_rnd_prec
;
1303 a
= floatx80_move(a
, status
);
1305 float_raise(float_flag_inexact
, status
);
1310 fp1
= floatx80_mul(fp0
, float64_to_floatx80(
1311 make_float64(0x3FE45F306DC9C883), status
),
1312 status
); /* X*2/PI */
1314 n
= floatx80_to_int32(fp1
, status
);
1317 fp0
= floatx80_sub(fp0
, pi_tbl
[j
], status
); /* X-Y1 */
1318 fp0
= floatx80_sub(fp0
, float32_to_floatx80(pi_tbl2
[j
], status
),
1319 status
); /* FP0 IS R = (X-Y1)-Y2 */
1325 fp0
= floatx80_mul(fp0
, fp0
, status
); /* S = R*R */
1326 fp3
= float64_to_floatx80(make_float64(0x3EA0B759F50F8688),
1328 fp2
= float64_to_floatx80(make_float64(0xBEF2BAA5A8924F04),
1330 fp3
= floatx80_mul(fp3
, fp0
, status
); /* SQ4 */
1331 fp2
= floatx80_mul(fp2
, fp0
, status
); /* SP3 */
1332 fp3
= floatx80_add(fp3
, float64_to_floatx80(
1333 make_float64(0xBF346F59B39BA65F), status
),
1334 status
); /* Q3+SQ4 */
1335 fp4
= packFloatx80(0, 0x3FF6, UINT64_C(0xE073D3FC199C4A00));
1336 fp2
= floatx80_add(fp2
, fp4
, status
); /* P2+SP3 */
1337 fp3
= floatx80_mul(fp3
, fp0
, status
); /* S(Q3+SQ4) */
1338 fp2
= floatx80_mul(fp2
, fp0
, status
); /* S(P2+SP3) */
1339 fp4
= packFloatx80(0, 0x3FF9, UINT64_C(0xD23CD68415D95FA1));
1340 fp3
= floatx80_add(fp3
, fp4
, status
); /* Q2+S(Q3+SQ4) */
1341 fp4
= packFloatx80(1, 0x3FFC, UINT64_C(0x8895A6C5FB423BCA));
1342 fp2
= floatx80_add(fp2
, fp4
, status
); /* P1+S(P2+SP3) */
1343 fp3
= floatx80_mul(fp3
, fp0
, status
); /* S(Q2+S(Q3+SQ4)) */
1344 fp2
= floatx80_mul(fp2
, fp0
, status
); /* S(P1+S(P2+SP3)) */
1345 fp4
= packFloatx80(1, 0x3FFD, UINT64_C(0xEEF57E0DA84BC8CE));
1346 fp3
= floatx80_add(fp3
, fp4
, status
); /* Q1+S(Q2+S(Q3+SQ4)) */
1347 fp2
= floatx80_mul(fp2
, fp1
, status
); /* RS(P1+S(P2+SP3)) */
1348 fp0
= floatx80_mul(fp0
, fp3
, status
); /* S(Q1+S(Q2+S(Q3+SQ4))) */
1349 fp1
= floatx80_add(fp1
, fp2
, status
); /* R+RS(P1+S(P2+SP3)) */
1350 fp0
= floatx80_add(fp0
, float32_to_floatx80(
1351 make_float32(0x3F800000), status
),
1352 status
); /* 1+S(Q1+S(Q2+S(Q3+SQ4))) */
1354 xSign
= extractFloatx80Sign(fp1
);
1355 xExp
= extractFloatx80Exp(fp1
);
1356 xSig
= extractFloatx80Frac(fp1
);
1358 fp1
= packFloatx80(xSign
, xExp
, xSig
);
1360 status
->float_rounding_mode
= user_rnd_mode
;
1361 status
->floatx80_rounding_precision
= user_rnd_prec
;
1363 a
= floatx80_div(fp0
, fp1
, status
);
1365 float_raise(float_flag_inexact
, status
);
1369 fp1
= floatx80_mul(fp0
, fp0
, status
); /* S = R*R */
1370 fp3
= float64_to_floatx80(make_float64(0x3EA0B759F50F8688),
1372 fp2
= float64_to_floatx80(make_float64(0xBEF2BAA5A8924F04),
1374 fp3
= floatx80_mul(fp3
, fp1
, status
); /* SQ4 */
1375 fp2
= floatx80_mul(fp2
, fp1
, status
); /* SP3 */
1376 fp3
= floatx80_add(fp3
, float64_to_floatx80(
1377 make_float64(0xBF346F59B39BA65F), status
),
1378 status
); /* Q3+SQ4 */
1379 fp4
= packFloatx80(0, 0x3FF6, UINT64_C(0xE073D3FC199C4A00));
1380 fp2
= floatx80_add(fp2
, fp4
, status
); /* P2+SP3 */
1381 fp3
= floatx80_mul(fp3
, fp1
, status
); /* S(Q3+SQ4) */
1382 fp2
= floatx80_mul(fp2
, fp1
, status
); /* S(P2+SP3) */
1383 fp4
= packFloatx80(0, 0x3FF9, UINT64_C(0xD23CD68415D95FA1));
1384 fp3
= floatx80_add(fp3
, fp4
, status
); /* Q2+S(Q3+SQ4) */
1385 fp4
= packFloatx80(1, 0x3FFC, UINT64_C(0x8895A6C5FB423BCA));
1386 fp2
= floatx80_add(fp2
, fp4
, status
); /* P1+S(P2+SP3) */
1387 fp3
= floatx80_mul(fp3
, fp1
, status
); /* S(Q2+S(Q3+SQ4)) */
1388 fp2
= floatx80_mul(fp2
, fp1
, status
); /* S(P1+S(P2+SP3)) */
1389 fp4
= packFloatx80(1, 0x3FFD, UINT64_C(0xEEF57E0DA84BC8CE));
1390 fp3
= floatx80_add(fp3
, fp4
, status
); /* Q1+S(Q2+S(Q3+SQ4)) */
1391 fp2
= floatx80_mul(fp2
, fp0
, status
); /* RS(P1+S(P2+SP3)) */
1392 fp1
= floatx80_mul(fp1
, fp3
, status
); /* S(Q1+S(Q2+S(Q3+SQ4))) */
1393 fp0
= floatx80_add(fp0
, fp2
, status
); /* R+RS(P1+S(P2+SP3)) */
1394 fp1
= floatx80_add(fp1
, float32_to_floatx80(
1395 make_float32(0x3F800000), status
),
1396 status
); /* 1+S(Q1+S(Q2+S(Q3+SQ4))) */
1398 status
->float_rounding_mode
= user_rnd_mode
;
1399 status
->floatx80_rounding_precision
= user_rnd_prec
;
1401 a
= floatx80_div(fp0
, fp1
, status
);
1403 float_raise(float_flag_inexact
, status
);
1414 floatx80
floatx80_sin(floatx80 a
, float_status
*status
)
1418 uint64_t aSig
, xSig
;
1420 int8_t user_rnd_mode
, user_rnd_prec
;
1422 int32_t compact
, l
, n
, j
;
1423 floatx80 fp0
, fp1
, fp2
, fp3
, fp4
, fp5
, x
, invtwopi
, twopi1
, twopi2
;
1424 float32 posneg1
, twoto63
;
1427 aSig
= extractFloatx80Frac(a
);
1428 aExp
= extractFloatx80Exp(a
);
1429 aSign
= extractFloatx80Sign(a
);
1431 if (aExp
== 0x7FFF) {
1432 if ((uint64_t) (aSig
<< 1)) {
1433 return propagateFloatx80NaNOneArg(a
, status
);
1435 float_raise(float_flag_invalid
, status
);
1436 return floatx80_default_nan(status
);
1439 if (aExp
== 0 && aSig
== 0) {
1440 return packFloatx80(aSign
, 0, 0);
1443 user_rnd_mode
= status
->float_rounding_mode
;
1444 user_rnd_prec
= status
->floatx80_rounding_precision
;
1445 status
->float_rounding_mode
= float_round_nearest_even
;
1446 status
->floatx80_rounding_precision
= 80;
1448 compact
= floatx80_make_compact(aExp
, aSig
);
1452 if (compact
< 0x3FD78000 || compact
> 0x4004BC7E) {
1453 /* 2^(-40) > |X| > 15 PI */
1454 if (compact
> 0x3FFF8000) { /* |X| >= 15 PI */
1456 fp1
= packFloatx80(0, 0, 0);
1457 if (compact
== 0x7FFEFFFF) {
1458 twopi1
= packFloatx80(aSign
^ 1, 0x7FFE,
1459 UINT64_C(0xC90FDAA200000000));
1460 twopi2
= packFloatx80(aSign
^ 1, 0x7FDC,
1461 UINT64_C(0x85A308D300000000));
1462 fp0
= floatx80_add(fp0
, twopi1
, status
);
1464 fp0
= floatx80_add(fp0
, twopi2
, status
);
1465 fp1
= floatx80_sub(fp1
, fp0
, status
);
1466 fp1
= floatx80_add(fp1
, twopi2
, status
);
1469 xSign
= extractFloatx80Sign(fp0
);
1470 xExp
= extractFloatx80Exp(fp0
);
1479 invtwopi
= packFloatx80(0, 0x3FFE - l
,
1480 UINT64_C(0xA2F9836E4E44152A)); /* INVTWOPI */
1481 twopi1
= packFloatx80(0, 0x3FFF + l
, UINT64_C(0xC90FDAA200000000));
1482 twopi2
= packFloatx80(0, 0x3FDD + l
, UINT64_C(0x85A308D300000000));
1484 /* SIGN(INARG)*2^63 IN SGL */
1485 twoto63
= packFloat32(xSign
, 0xBE, 0);
1487 fp2
= floatx80_mul(fp0
, invtwopi
, status
);
1488 fp2
= floatx80_add(fp2
, float32_to_floatx80(twoto63
, status
),
1489 status
); /* THE FRACT PART OF FP2 IS ROUNDED */
1490 fp2
= floatx80_sub(fp2
, float32_to_floatx80(twoto63
, status
),
1491 status
); /* FP2 is N */
1492 fp4
= floatx80_mul(twopi1
, fp2
, status
); /* W = N*P1 */
1493 fp5
= floatx80_mul(twopi2
, fp2
, status
); /* w = N*P2 */
1494 fp3
= floatx80_add(fp4
, fp5
, status
); /* FP3 is P */
1495 fp4
= floatx80_sub(fp4
, fp3
, status
); /* W-P */
1496 fp0
= floatx80_sub(fp0
, fp3
, status
); /* FP0 is A := R - P */
1497 fp4
= floatx80_add(fp4
, fp5
, status
); /* FP4 is p = (W-P)+w */
1498 fp3
= fp0
; /* FP3 is A */
1499 fp1
= floatx80_sub(fp1
, fp4
, status
); /* FP1 is a := r - p */
1500 fp0
= floatx80_add(fp0
, fp1
, status
); /* FP0 is R := A+a */
1503 n
= floatx80_to_int32(fp2
, status
);
1506 fp3
= floatx80_sub(fp3
, fp0
, status
); /* A-R */
1507 fp1
= floatx80_add(fp1
, fp3
, status
); /* FP1 is r := (A-R)+a */
1511 fp0
= float32_to_floatx80(make_float32(0x3F800000),
1514 status
->float_rounding_mode
= user_rnd_mode
;
1515 status
->floatx80_rounding_precision
= user_rnd_prec
;
1518 a
= floatx80_move(a
, status
);
1519 float_raise(float_flag_inexact
, status
);
1524 fp1
= floatx80_mul(fp0
, float64_to_floatx80(
1525 make_float64(0x3FE45F306DC9C883), status
),
1526 status
); /* X*2/PI */
1528 n
= floatx80_to_int32(fp1
, status
);
1531 fp0
= floatx80_sub(fp0
, pi_tbl
[j
], status
); /* X-Y1 */
1532 fp0
= floatx80_sub(fp0
, float32_to_floatx80(pi_tbl2
[j
], status
),
1533 status
); /* FP0 IS R = (X-Y1)-Y2 */
1538 fp0
= floatx80_mul(fp0
, fp0
, status
); /* FP0 IS S */
1539 fp1
= floatx80_mul(fp0
, fp0
, status
); /* FP1 IS T */
1540 fp2
= float64_to_floatx80(make_float64(0x3D2AC4D0D6011EE3),
1542 fp3
= float64_to_floatx80(make_float64(0xBDA9396F9F45AC19),
1545 xSign
= extractFloatx80Sign(fp0
); /* X IS S */
1546 xExp
= extractFloatx80Exp(fp0
);
1547 xSig
= extractFloatx80Frac(fp0
);
1551 posneg1
= make_float32(0xBF800000); /* -1 */
1554 posneg1
= make_float32(0x3F800000); /* 1 */
1555 } /* X IS NOW R'= SGN*R */
1557 fp2
= floatx80_mul(fp2
, fp1
, status
); /* TB8 */
1558 fp3
= floatx80_mul(fp3
, fp1
, status
); /* TB7 */
1559 fp2
= floatx80_add(fp2
, float64_to_floatx80(
1560 make_float64(0x3E21EED90612C972), status
),
1561 status
); /* B6+TB8 */
1562 fp3
= floatx80_add(fp3
, float64_to_floatx80(
1563 make_float64(0xBE927E4FB79D9FCF), status
),
1564 status
); /* B5+TB7 */
1565 fp2
= floatx80_mul(fp2
, fp1
, status
); /* T(B6+TB8) */
1566 fp3
= floatx80_mul(fp3
, fp1
, status
); /* T(B5+TB7) */
1567 fp2
= floatx80_add(fp2
, float64_to_floatx80(
1568 make_float64(0x3EFA01A01A01D423), status
),
1569 status
); /* B4+T(B6+TB8) */
1570 fp4
= packFloatx80(1, 0x3FF5, UINT64_C(0xB60B60B60B61D438));
1571 fp3
= floatx80_add(fp3
, fp4
, status
); /* B3+T(B5+TB7) */
1572 fp2
= floatx80_mul(fp2
, fp1
, status
); /* T(B4+T(B6+TB8)) */
1573 fp1
= floatx80_mul(fp1
, fp3
, status
); /* T(B3+T(B5+TB7)) */
1574 fp4
= packFloatx80(0, 0x3FFA, UINT64_C(0xAAAAAAAAAAAAAB5E));
1575 fp2
= floatx80_add(fp2
, fp4
, status
); /* B2+T(B4+T(B6+TB8)) */
1576 fp1
= floatx80_add(fp1
, float32_to_floatx80(
1577 make_float32(0xBF000000), status
),
1578 status
); /* B1+T(B3+T(B5+TB7)) */
1579 fp0
= floatx80_mul(fp0
, fp2
, status
); /* S(B2+T(B4+T(B6+TB8))) */
1580 fp0
= floatx80_add(fp0
, fp1
, status
); /* [B1+T(B3+T(B5+TB7))]+
1581 * [S(B2+T(B4+T(B6+TB8)))]
1584 x
= packFloatx80(xSign
, xExp
, xSig
);
1585 fp0
= floatx80_mul(fp0
, x
, status
);
1587 status
->float_rounding_mode
= user_rnd_mode
;
1588 status
->floatx80_rounding_precision
= user_rnd_prec
;
1590 a
= floatx80_add(fp0
, float32_to_floatx80(posneg1
, status
), status
);
1592 float_raise(float_flag_inexact
, status
);
1597 xSign
= extractFloatx80Sign(fp0
); /* X IS R */
1598 xExp
= extractFloatx80Exp(fp0
);
1599 xSig
= extractFloatx80Frac(fp0
);
1601 xSign
^= (n
>> 1) & 1; /* X IS NOW R'= SGN*R */
1603 fp0
= floatx80_mul(fp0
, fp0
, status
); /* FP0 IS S */
1604 fp1
= floatx80_mul(fp0
, fp0
, status
); /* FP1 IS T */
1605 fp3
= float64_to_floatx80(make_float64(0xBD6AAA77CCC994F5),
1607 fp2
= float64_to_floatx80(make_float64(0x3DE612097AAE8DA1),
1609 fp3
= floatx80_mul(fp3
, fp1
, status
); /* T*A7 */
1610 fp2
= floatx80_mul(fp2
, fp1
, status
); /* T*A6 */
1611 fp3
= floatx80_add(fp3
, float64_to_floatx80(
1612 make_float64(0xBE5AE6452A118AE4), status
),
1613 status
); /* A5+T*A7 */
1614 fp2
= floatx80_add(fp2
, float64_to_floatx80(
1615 make_float64(0x3EC71DE3A5341531), status
),
1616 status
); /* A4+T*A6 */
1617 fp3
= floatx80_mul(fp3
, fp1
, status
); /* T(A5+TA7) */
1618 fp2
= floatx80_mul(fp2
, fp1
, status
); /* T(A4+TA6) */
1619 fp3
= floatx80_add(fp3
, float64_to_floatx80(
1620 make_float64(0xBF2A01A01A018B59), status
),
1621 status
); /* A3+T(A5+TA7) */
1622 fp4
= packFloatx80(0, 0x3FF8, UINT64_C(0x88888888888859AF));
1623 fp2
= floatx80_add(fp2
, fp4
, status
); /* A2+T(A4+TA6) */
1624 fp1
= floatx80_mul(fp1
, fp3
, status
); /* T(A3+T(A5+TA7)) */
1625 fp2
= floatx80_mul(fp2
, fp0
, status
); /* S(A2+T(A4+TA6)) */
1626 fp4
= packFloatx80(1, 0x3FFC, UINT64_C(0xAAAAAAAAAAAAAA99));
1627 fp1
= floatx80_add(fp1
, fp4
, status
); /* A1+T(A3+T(A5+TA7)) */
1628 fp1
= floatx80_add(fp1
, fp2
,
1629 status
); /* [A1+T(A3+T(A5+TA7))]+
1633 x
= packFloatx80(xSign
, xExp
, xSig
);
1634 fp0
= floatx80_mul(fp0
, x
, status
); /* R'*S */
1635 fp0
= floatx80_mul(fp0
, fp1
, status
); /* SIN(R')-R' */
1637 status
->float_rounding_mode
= user_rnd_mode
;
1638 status
->floatx80_rounding_precision
= user_rnd_prec
;
1640 a
= floatx80_add(fp0
, x
, status
);
1642 float_raise(float_flag_inexact
, status
);
1653 floatx80
floatx80_cos(floatx80 a
, float_status
*status
)
1657 uint64_t aSig
, xSig
;
1659 int8_t user_rnd_mode
, user_rnd_prec
;
1661 int32_t compact
, l
, n
, j
;
1662 floatx80 fp0
, fp1
, fp2
, fp3
, fp4
, fp5
, x
, invtwopi
, twopi1
, twopi2
;
1663 float32 posneg1
, twoto63
;
1666 aSig
= extractFloatx80Frac(a
);
1667 aExp
= extractFloatx80Exp(a
);
1668 aSign
= extractFloatx80Sign(a
);
1670 if (aExp
== 0x7FFF) {
1671 if ((uint64_t) (aSig
<< 1)) {
1672 return propagateFloatx80NaNOneArg(a
, status
);
1674 float_raise(float_flag_invalid
, status
);
1675 return floatx80_default_nan(status
);
1678 if (aExp
== 0 && aSig
== 0) {
1679 return packFloatx80(0, one_exp
, one_sig
);
1682 user_rnd_mode
= status
->float_rounding_mode
;
1683 user_rnd_prec
= status
->floatx80_rounding_precision
;
1684 status
->float_rounding_mode
= float_round_nearest_even
;
1685 status
->floatx80_rounding_precision
= 80;
1687 compact
= floatx80_make_compact(aExp
, aSig
);
1691 if (compact
< 0x3FD78000 || compact
> 0x4004BC7E) {
1692 /* 2^(-40) > |X| > 15 PI */
1693 if (compact
> 0x3FFF8000) { /* |X| >= 15 PI */
1695 fp1
= packFloatx80(0, 0, 0);
1696 if (compact
== 0x7FFEFFFF) {
1697 twopi1
= packFloatx80(aSign
^ 1, 0x7FFE,
1698 UINT64_C(0xC90FDAA200000000));
1699 twopi2
= packFloatx80(aSign
^ 1, 0x7FDC,
1700 UINT64_C(0x85A308D300000000));
1701 fp0
= floatx80_add(fp0
, twopi1
, status
);
1703 fp0
= floatx80_add(fp0
, twopi2
, status
);
1704 fp1
= floatx80_sub(fp1
, fp0
, status
);
1705 fp1
= floatx80_add(fp1
, twopi2
, status
);
1708 xSign
= extractFloatx80Sign(fp0
);
1709 xExp
= extractFloatx80Exp(fp0
);
1718 invtwopi
= packFloatx80(0, 0x3FFE - l
,
1719 UINT64_C(0xA2F9836E4E44152A)); /* INVTWOPI */
1720 twopi1
= packFloatx80(0, 0x3FFF + l
, UINT64_C(0xC90FDAA200000000));
1721 twopi2
= packFloatx80(0, 0x3FDD + l
, UINT64_C(0x85A308D300000000));
1723 /* SIGN(INARG)*2^63 IN SGL */
1724 twoto63
= packFloat32(xSign
, 0xBE, 0);
1726 fp2
= floatx80_mul(fp0
, invtwopi
, status
);
1727 fp2
= floatx80_add(fp2
, float32_to_floatx80(twoto63
, status
),
1728 status
); /* THE FRACT PART OF FP2 IS ROUNDED */
1729 fp2
= floatx80_sub(fp2
, float32_to_floatx80(twoto63
, status
),
1730 status
); /* FP2 is N */
1731 fp4
= floatx80_mul(twopi1
, fp2
, status
); /* W = N*P1 */
1732 fp5
= floatx80_mul(twopi2
, fp2
, status
); /* w = N*P2 */
1733 fp3
= floatx80_add(fp4
, fp5
, status
); /* FP3 is P */
1734 fp4
= floatx80_sub(fp4
, fp3
, status
); /* W-P */
1735 fp0
= floatx80_sub(fp0
, fp3
, status
); /* FP0 is A := R - P */
1736 fp4
= floatx80_add(fp4
, fp5
, status
); /* FP4 is p = (W-P)+w */
1737 fp3
= fp0
; /* FP3 is A */
1738 fp1
= floatx80_sub(fp1
, fp4
, status
); /* FP1 is a := r - p */
1739 fp0
= floatx80_add(fp0
, fp1
, status
); /* FP0 is R := A+a */
1742 n
= floatx80_to_int32(fp2
, status
);
1745 fp3
= floatx80_sub(fp3
, fp0
, status
); /* A-R */
1746 fp1
= floatx80_add(fp1
, fp3
, status
); /* FP1 is r := (A-R)+a */
1750 fp0
= float32_to_floatx80(make_float32(0x3F800000), status
); /* 1 */
1752 status
->float_rounding_mode
= user_rnd_mode
;
1753 status
->floatx80_rounding_precision
= user_rnd_prec
;
1756 a
= floatx80_sub(fp0
, float32_to_floatx80(
1757 make_float32(0x00800000), status
),
1759 float_raise(float_flag_inexact
, status
);
1764 fp1
= floatx80_mul(fp0
, float64_to_floatx80(
1765 make_float64(0x3FE45F306DC9C883), status
),
1766 status
); /* X*2/PI */
1768 n
= floatx80_to_int32(fp1
, status
);
1771 fp0
= floatx80_sub(fp0
, pi_tbl
[j
], status
); /* X-Y1 */
1772 fp0
= floatx80_sub(fp0
, float32_to_floatx80(pi_tbl2
[j
], status
),
1773 status
); /* FP0 IS R = (X-Y1)-Y2 */
1778 fp0
= floatx80_mul(fp0
, fp0
, status
); /* FP0 IS S */
1779 fp1
= floatx80_mul(fp0
, fp0
, status
); /* FP1 IS T */
1780 fp2
= float64_to_floatx80(make_float64(0x3D2AC4D0D6011EE3),
1782 fp3
= float64_to_floatx80(make_float64(0xBDA9396F9F45AC19),
1785 xSign
= extractFloatx80Sign(fp0
); /* X IS S */
1786 xExp
= extractFloatx80Exp(fp0
);
1787 xSig
= extractFloatx80Frac(fp0
);
1789 if (((n
+ 1) >> 1) & 1) {
1791 posneg1
= make_float32(0xBF800000); /* -1 */
1794 posneg1
= make_float32(0x3F800000); /* 1 */
1795 } /* X IS NOW R'= SGN*R */
1797 fp2
= floatx80_mul(fp2
, fp1
, status
); /* TB8 */
1798 fp3
= floatx80_mul(fp3
, fp1
, status
); /* TB7 */
1799 fp2
= floatx80_add(fp2
, float64_to_floatx80(
1800 make_float64(0x3E21EED90612C972), status
),
1801 status
); /* B6+TB8 */
1802 fp3
= floatx80_add(fp3
, float64_to_floatx80(
1803 make_float64(0xBE927E4FB79D9FCF), status
),
1804 status
); /* B5+TB7 */
1805 fp2
= floatx80_mul(fp2
, fp1
, status
); /* T(B6+TB8) */
1806 fp3
= floatx80_mul(fp3
, fp1
, status
); /* T(B5+TB7) */
1807 fp2
= floatx80_add(fp2
, float64_to_floatx80(
1808 make_float64(0x3EFA01A01A01D423), status
),
1809 status
); /* B4+T(B6+TB8) */
1810 fp4
= packFloatx80(1, 0x3FF5, UINT64_C(0xB60B60B60B61D438));
1811 fp3
= floatx80_add(fp3
, fp4
, status
); /* B3+T(B5+TB7) */
1812 fp2
= floatx80_mul(fp2
, fp1
, status
); /* T(B4+T(B6+TB8)) */
1813 fp1
= floatx80_mul(fp1
, fp3
, status
); /* T(B3+T(B5+TB7)) */
1814 fp4
= packFloatx80(0, 0x3FFA, UINT64_C(0xAAAAAAAAAAAAAB5E));
1815 fp2
= floatx80_add(fp2
, fp4
, status
); /* B2+T(B4+T(B6+TB8)) */
1816 fp1
= floatx80_add(fp1
, float32_to_floatx80(
1817 make_float32(0xBF000000), status
),
1818 status
); /* B1+T(B3+T(B5+TB7)) */
1819 fp0
= floatx80_mul(fp0
, fp2
, status
); /* S(B2+T(B4+T(B6+TB8))) */
1820 fp0
= floatx80_add(fp0
, fp1
, status
);
1821 /* [B1+T(B3+T(B5+TB7))]+[S(B2+T(B4+T(B6+TB8)))] */
1823 x
= packFloatx80(xSign
, xExp
, xSig
);
1824 fp0
= floatx80_mul(fp0
, x
, status
);
1826 status
->float_rounding_mode
= user_rnd_mode
;
1827 status
->floatx80_rounding_precision
= user_rnd_prec
;
1829 a
= floatx80_add(fp0
, float32_to_floatx80(posneg1
, status
), status
);
1831 float_raise(float_flag_inexact
, status
);
1836 xSign
= extractFloatx80Sign(fp0
); /* X IS R */
1837 xExp
= extractFloatx80Exp(fp0
);
1838 xSig
= extractFloatx80Frac(fp0
);
1840 xSign
^= ((n
+ 1) >> 1) & 1; /* X IS NOW R'= SGN*R */
1842 fp0
= floatx80_mul(fp0
, fp0
, status
); /* FP0 IS S */
1843 fp1
= floatx80_mul(fp0
, fp0
, status
); /* FP1 IS T */
1844 fp3
= float64_to_floatx80(make_float64(0xBD6AAA77CCC994F5),
1846 fp2
= float64_to_floatx80(make_float64(0x3DE612097AAE8DA1),
1848 fp3
= floatx80_mul(fp3
, fp1
, status
); /* T*A7 */
1849 fp2
= floatx80_mul(fp2
, fp1
, status
); /* T*A6 */
1850 fp3
= floatx80_add(fp3
, float64_to_floatx80(
1851 make_float64(0xBE5AE6452A118AE4), status
),
1852 status
); /* A5+T*A7 */
1853 fp2
= floatx80_add(fp2
, float64_to_floatx80(
1854 make_float64(0x3EC71DE3A5341531), status
),
1855 status
); /* A4+T*A6 */
1856 fp3
= floatx80_mul(fp3
, fp1
, status
); /* T(A5+TA7) */
1857 fp2
= floatx80_mul(fp2
, fp1
, status
); /* T(A4+TA6) */
1858 fp3
= floatx80_add(fp3
, float64_to_floatx80(
1859 make_float64(0xBF2A01A01A018B59), status
),
1860 status
); /* A3+T(A5+TA7) */
1861 fp4
= packFloatx80(0, 0x3FF8, UINT64_C(0x88888888888859AF));
1862 fp2
= floatx80_add(fp2
, fp4
, status
); /* A2+T(A4+TA6) */
1863 fp1
= floatx80_mul(fp1
, fp3
, status
); /* T(A3+T(A5+TA7)) */
1864 fp2
= floatx80_mul(fp2
, fp0
, status
); /* S(A2+T(A4+TA6)) */
1865 fp4
= packFloatx80(1, 0x3FFC, UINT64_C(0xAAAAAAAAAAAAAA99));
1866 fp1
= floatx80_add(fp1
, fp4
, status
); /* A1+T(A3+T(A5+TA7)) */
1867 fp1
= floatx80_add(fp1
, fp2
, status
);
1868 /* [A1+T(A3+T(A5+TA7))]+[S(A2+T(A4+TA6))] */
1870 x
= packFloatx80(xSign
, xExp
, xSig
);
1871 fp0
= floatx80_mul(fp0
, x
, status
); /* R'*S */
1872 fp0
= floatx80_mul(fp0
, fp1
, status
); /* SIN(R')-R' */
1874 status
->float_rounding_mode
= user_rnd_mode
;
1875 status
->floatx80_rounding_precision
= user_rnd_prec
;
1877 a
= floatx80_add(fp0
, x
, status
);
1879 float_raise(float_flag_inexact
, status
);
1890 floatx80
floatx80_atan(floatx80 a
, float_status
*status
)
1896 int8_t user_rnd_mode
, user_rnd_prec
;
1898 int32_t compact
, tbl_index
;
1899 floatx80 fp0
, fp1
, fp2
, fp3
, xsave
;
1901 aSig
= extractFloatx80Frac(a
);
1902 aExp
= extractFloatx80Exp(a
);
1903 aSign
= extractFloatx80Sign(a
);
1905 if (aExp
== 0x7FFF) {
1906 if ((uint64_t) (aSig
<< 1)) {
1907 return propagateFloatx80NaNOneArg(a
, status
);
1909 a
= packFloatx80(aSign
, piby2_exp
, pi_sig
);
1910 float_raise(float_flag_inexact
, status
);
1911 return floatx80_move(a
, status
);
1914 if (aExp
== 0 && aSig
== 0) {
1915 return packFloatx80(aSign
, 0, 0);
1918 compact
= floatx80_make_compact(aExp
, aSig
);
1920 user_rnd_mode
= status
->float_rounding_mode
;
1921 user_rnd_prec
= status
->floatx80_rounding_precision
;
1922 status
->float_rounding_mode
= float_round_nearest_even
;
1923 status
->floatx80_rounding_precision
= 80;
1925 if (compact
< 0x3FFB8000 || compact
> 0x4002FFFF) {
1926 /* |X| >= 16 or |X| < 1/16 */
1927 if (compact
> 0x3FFF8000) { /* |X| >= 16 */
1928 if (compact
> 0x40638000) { /* |X| > 2^(100) */
1929 fp0
= packFloatx80(aSign
, piby2_exp
, pi_sig
);
1930 fp1
= packFloatx80(aSign
, 0x0001, one_sig
);
1932 status
->float_rounding_mode
= user_rnd_mode
;
1933 status
->floatx80_rounding_precision
= user_rnd_prec
;
1935 a
= floatx80_sub(fp0
, fp1
, status
);
1937 float_raise(float_flag_inexact
, status
);
1942 fp1
= packFloatx80(1, one_exp
, one_sig
); /* -1 */
1943 fp1
= floatx80_div(fp1
, fp0
, status
); /* X' = -1/X */
1945 fp0
= floatx80_mul(fp1
, fp1
, status
); /* Y = X'*X' */
1946 fp1
= floatx80_mul(fp0
, fp0
, status
); /* Z = Y*Y */
1947 fp3
= float64_to_floatx80(make_float64(0xBFB70BF398539E6A),
1949 fp2
= float64_to_floatx80(make_float64(0x3FBC7187962D1D7D),
1951 fp3
= floatx80_mul(fp3
, fp1
, status
); /* Z*C5 */
1952 fp2
= floatx80_mul(fp2
, fp1
, status
); /* Z*C4 */
1953 fp3
= floatx80_add(fp3
, float64_to_floatx80(
1954 make_float64(0xBFC24924827107B8), status
),
1955 status
); /* C3+Z*C5 */
1956 fp2
= floatx80_add(fp2
, float64_to_floatx80(
1957 make_float64(0x3FC999999996263E), status
),
1958 status
); /* C2+Z*C4 */
1959 fp1
= floatx80_mul(fp1
, fp3
, status
); /* Z*(C3+Z*C5) */
1960 fp2
= floatx80_mul(fp2
, fp0
, status
); /* Y*(C2+Z*C4) */
1961 fp1
= floatx80_add(fp1
, float64_to_floatx80(
1962 make_float64(0xBFD5555555555536), status
),
1963 status
); /* C1+Z*(C3+Z*C5) */
1964 fp0
= floatx80_mul(fp0
, xsave
, status
); /* X'*Y */
1965 /* [Y*(C2+Z*C4)]+[C1+Z*(C3+Z*C5)] */
1966 fp1
= floatx80_add(fp1
, fp2
, status
);
1967 /* X'*Y*([B1+Z*(B3+Z*B5)]+[Y*(B2+Z*(B4+Z*B6))]) ?? */
1968 fp0
= floatx80_mul(fp0
, fp1
, status
);
1969 fp0
= floatx80_add(fp0
, xsave
, status
);
1970 fp1
= packFloatx80(aSign
, piby2_exp
, pi_sig
);
1972 status
->float_rounding_mode
= user_rnd_mode
;
1973 status
->floatx80_rounding_precision
= user_rnd_prec
;
1975 a
= floatx80_add(fp0
, fp1
, status
);
1977 float_raise(float_flag_inexact
, status
);
1981 } else { /* |X| < 1/16 */
1982 if (compact
< 0x3FD78000) { /* |X| < 2^(-40) */
1983 status
->float_rounding_mode
= user_rnd_mode
;
1984 status
->floatx80_rounding_precision
= user_rnd_prec
;
1986 a
= floatx80_move(a
, status
);
1988 float_raise(float_flag_inexact
, status
);
1994 fp0
= floatx80_mul(fp0
, fp0
, status
); /* Y = X*X */
1995 fp1
= floatx80_mul(fp0
, fp0
, status
); /* Z = Y*Y */
1996 fp2
= float64_to_floatx80(make_float64(0x3FB344447F876989),
1998 fp3
= float64_to_floatx80(make_float64(0xBFB744EE7FAF45DB),
2000 fp2
= floatx80_mul(fp2
, fp1
, status
); /* Z*B6 */
2001 fp3
= floatx80_mul(fp3
, fp1
, status
); /* Z*B5 */
2002 fp2
= floatx80_add(fp2
, float64_to_floatx80(
2003 make_float64(0x3FBC71C646940220), status
),
2004 status
); /* B4+Z*B6 */
2005 fp3
= floatx80_add(fp3
, float64_to_floatx80(
2006 make_float64(0xBFC24924921872F9),
2007 status
), status
); /* B3+Z*B5 */
2008 fp2
= floatx80_mul(fp2
, fp1
, status
); /* Z*(B4+Z*B6) */
2009 fp1
= floatx80_mul(fp1
, fp3
, status
); /* Z*(B3+Z*B5) */
2010 fp2
= floatx80_add(fp2
, float64_to_floatx80(
2011 make_float64(0x3FC9999999998FA9), status
),
2012 status
); /* B2+Z*(B4+Z*B6) */
2013 fp1
= floatx80_add(fp1
, float64_to_floatx80(
2014 make_float64(0xBFD5555555555555), status
),
2015 status
); /* B1+Z*(B3+Z*B5) */
2016 fp2
= floatx80_mul(fp2
, fp0
, status
); /* Y*(B2+Z*(B4+Z*B6)) */
2017 fp0
= floatx80_mul(fp0
, xsave
, status
); /* X*Y */
2018 /* [B1+Z*(B3+Z*B5)]+[Y*(B2+Z*(B4+Z*B6))] */
2019 fp1
= floatx80_add(fp1
, fp2
, status
);
2020 /* X*Y*([B1+Z*(B3+Z*B5)]+[Y*(B2+Z*(B4+Z*B6))]) */
2021 fp0
= floatx80_mul(fp0
, fp1
, status
);
2023 status
->float_rounding_mode
= user_rnd_mode
;
2024 status
->floatx80_rounding_precision
= user_rnd_prec
;
2026 a
= floatx80_add(fp0
, xsave
, status
);
2028 float_raise(float_flag_inexact
, status
);
2034 aSig
&= UINT64_C(0xF800000000000000);
2035 aSig
|= UINT64_C(0x0400000000000000);
2036 xsave
= packFloatx80(aSign
, aExp
, aSig
); /* F */
2039 fp2
= packFloatx80(0, one_exp
, one_sig
); /* 1 */
2040 fp1
= floatx80_mul(fp1
, xsave
, status
); /* X*F */
2041 fp0
= floatx80_sub(fp0
, xsave
, status
); /* X-F */
2042 fp1
= floatx80_add(fp1
, fp2
, status
); /* 1 + X*F */
2043 fp0
= floatx80_div(fp0
, fp1
, status
); /* U = (X-F)/(1+X*F) */
2045 tbl_index
= compact
;
2047 tbl_index
&= 0x7FFF0000;
2048 tbl_index
-= 0x3FFB0000;
2050 tbl_index
+= compact
& 0x00007800;
2053 fp3
= atan_tbl
[tbl_index
];
2055 fp3
.high
|= aSign
? 0x8000 : 0; /* ATAN(F) */
2057 fp1
= floatx80_mul(fp0
, fp0
, status
); /* V = U*U */
2058 fp2
= float64_to_floatx80(make_float64(0xBFF6687E314987D8),
2060 fp2
= floatx80_add(fp2
, fp1
, status
); /* A3+V */
2061 fp2
= floatx80_mul(fp2
, fp1
, status
); /* V*(A3+V) */
2062 fp1
= floatx80_mul(fp1
, fp0
, status
); /* U*V */
2063 fp2
= floatx80_add(fp2
, float64_to_floatx80(
2064 make_float64(0x4002AC6934A26DB3), status
),
2065 status
); /* A2+V*(A3+V) */
2066 fp1
= floatx80_mul(fp1
, float64_to_floatx80(
2067 make_float64(0xBFC2476F4E1DA28E), status
),
2068 status
); /* A1+U*V */
2069 fp1
= floatx80_mul(fp1
, fp2
, status
); /* A1*U*V*(A2+V*(A3+V)) */
2070 fp0
= floatx80_add(fp0
, fp1
, status
); /* ATAN(U) */
2072 status
->float_rounding_mode
= user_rnd_mode
;
2073 status
->floatx80_rounding_precision
= user_rnd_prec
;
2075 a
= floatx80_add(fp0
, fp3
, status
); /* ATAN(X) */
2077 float_raise(float_flag_inexact
, status
);
2087 floatx80
floatx80_asin(floatx80 a
, float_status
*status
)
2093 int8_t user_rnd_mode
, user_rnd_prec
;
2096 floatx80 fp0
, fp1
, fp2
, one
;
2098 aSig
= extractFloatx80Frac(a
);
2099 aExp
= extractFloatx80Exp(a
);
2100 aSign
= extractFloatx80Sign(a
);
2102 if (aExp
== 0x7FFF && (uint64_t) (aSig
<< 1)) {
2103 return propagateFloatx80NaNOneArg(a
, status
);
2106 if (aExp
== 0 && aSig
== 0) {
2107 return packFloatx80(aSign
, 0, 0);
2110 compact
= floatx80_make_compact(aExp
, aSig
);
2112 if (compact
>= 0x3FFF8000) { /* |X| >= 1 */
2113 if (aExp
== one_exp
&& aSig
== one_sig
) { /* |X| == 1 */
2114 float_raise(float_flag_inexact
, status
);
2115 a
= packFloatx80(aSign
, piby2_exp
, pi_sig
);
2116 return floatx80_move(a
, status
);
2117 } else { /* |X| > 1 */
2118 float_raise(float_flag_invalid
, status
);
2119 return floatx80_default_nan(status
);
2124 user_rnd_mode
= status
->float_rounding_mode
;
2125 user_rnd_prec
= status
->floatx80_rounding_precision
;
2126 status
->float_rounding_mode
= float_round_nearest_even
;
2127 status
->floatx80_rounding_precision
= 80;
2129 one
= packFloatx80(0, one_exp
, one_sig
);
2132 fp1
= floatx80_sub(one
, fp0
, status
); /* 1 - X */
2133 fp2
= floatx80_add(one
, fp0
, status
); /* 1 + X */
2134 fp1
= floatx80_mul(fp2
, fp1
, status
); /* (1+X)*(1-X) */
2135 fp1
= floatx80_sqrt(fp1
, status
); /* SQRT((1+X)*(1-X)) */
2136 fp0
= floatx80_div(fp0
, fp1
, status
); /* X/SQRT((1+X)*(1-X)) */
2138 status
->float_rounding_mode
= user_rnd_mode
;
2139 status
->floatx80_rounding_precision
= user_rnd_prec
;
2141 a
= floatx80_atan(fp0
, status
); /* ATAN(X/SQRT((1+X)*(1-X))) */
2143 float_raise(float_flag_inexact
, status
);
2152 floatx80
floatx80_acos(floatx80 a
, float_status
*status
)
2158 int8_t user_rnd_mode
, user_rnd_prec
;
2161 floatx80 fp0
, fp1
, one
;
2163 aSig
= extractFloatx80Frac(a
);
2164 aExp
= extractFloatx80Exp(a
);
2165 aSign
= extractFloatx80Sign(a
);
2167 if (aExp
== 0x7FFF && (uint64_t) (aSig
<< 1)) {
2168 return propagateFloatx80NaNOneArg(a
, status
);
2170 if (aExp
== 0 && aSig
== 0) {
2171 float_raise(float_flag_inexact
, status
);
2172 return roundAndPackFloatx80(status
->floatx80_rounding_precision
, 0,
2173 piby2_exp
, pi_sig
, 0, status
);
2176 compact
= floatx80_make_compact(aExp
, aSig
);
2178 if (compact
>= 0x3FFF8000) { /* |X| >= 1 */
2179 if (aExp
== one_exp
&& aSig
== one_sig
) { /* |X| == 1 */
2180 if (aSign
) { /* X == -1 */
2181 a
= packFloatx80(0, pi_exp
, pi_sig
);
2182 float_raise(float_flag_inexact
, status
);
2183 return floatx80_move(a
, status
);
2184 } else { /* X == +1 */
2185 return packFloatx80(0, 0, 0);
2187 } else { /* |X| > 1 */
2188 float_raise(float_flag_invalid
, status
);
2189 return floatx80_default_nan(status
);
2193 user_rnd_mode
= status
->float_rounding_mode
;
2194 user_rnd_prec
= status
->floatx80_rounding_precision
;
2195 status
->float_rounding_mode
= float_round_nearest_even
;
2196 status
->floatx80_rounding_precision
= 80;
2198 one
= packFloatx80(0, one_exp
, one_sig
);
2201 fp1
= floatx80_add(one
, fp0
, status
); /* 1 + X */
2202 fp0
= floatx80_sub(one
, fp0
, status
); /* 1 - X */
2203 fp0
= floatx80_div(fp0
, fp1
, status
); /* (1-X)/(1+X) */
2204 fp0
= floatx80_sqrt(fp0
, status
); /* SQRT((1-X)/(1+X)) */
2205 fp0
= floatx80_atan(fp0
, status
); /* ATAN(SQRT((1-X)/(1+X))) */
2207 status
->float_rounding_mode
= user_rnd_mode
;
2208 status
->floatx80_rounding_precision
= user_rnd_prec
;
2210 a
= floatx80_add(fp0
, fp0
, status
); /* 2 * ATAN(SQRT((1-X)/(1+X))) */
2212 float_raise(float_flag_inexact
, status
);
2218 * Hyperbolic arc tangent
2221 floatx80
floatx80_atanh(floatx80 a
, float_status
*status
)
2227 int8_t user_rnd_mode
, user_rnd_prec
;
2230 floatx80 fp0
, fp1
, fp2
, one
;
2232 aSig
= extractFloatx80Frac(a
);
2233 aExp
= extractFloatx80Exp(a
);
2234 aSign
= extractFloatx80Sign(a
);
2236 if (aExp
== 0x7FFF && (uint64_t) (aSig
<< 1)) {
2237 return propagateFloatx80NaNOneArg(a
, status
);
2240 if (aExp
== 0 && aSig
== 0) {
2241 return packFloatx80(aSign
, 0, 0);
2244 compact
= floatx80_make_compact(aExp
, aSig
);
2246 if (compact
>= 0x3FFF8000) { /* |X| >= 1 */
2247 if (aExp
== one_exp
&& aSig
== one_sig
) { /* |X| == 1 */
2248 float_raise(float_flag_divbyzero
, status
);
2249 return packFloatx80(aSign
, floatx80_infinity
.high
,
2250 floatx80_infinity
.low
);
2251 } else { /* |X| > 1 */
2252 float_raise(float_flag_invalid
, status
);
2253 return floatx80_default_nan(status
);
2257 user_rnd_mode
= status
->float_rounding_mode
;
2258 user_rnd_prec
= status
->floatx80_rounding_precision
;
2259 status
->float_rounding_mode
= float_round_nearest_even
;
2260 status
->floatx80_rounding_precision
= 80;
2262 one
= packFloatx80(0, one_exp
, one_sig
);
2263 fp2
= packFloatx80(aSign
, 0x3FFE, one_sig
); /* SIGN(X) * (1/2) */
2264 fp0
= packFloatx80(0, aExp
, aSig
); /* Y = |X| */
2265 fp1
= packFloatx80(1, aExp
, aSig
); /* -Y */
2266 fp0
= floatx80_add(fp0
, fp0
, status
); /* 2Y */
2267 fp1
= floatx80_add(fp1
, one
, status
); /* 1-Y */
2268 fp0
= floatx80_div(fp0
, fp1
, status
); /* Z = 2Y/(1-Y) */
2269 fp0
= floatx80_lognp1(fp0
, status
); /* LOG1P(Z) */
2271 status
->float_rounding_mode
= user_rnd_mode
;
2272 status
->floatx80_rounding_precision
= user_rnd_prec
;
2274 a
= floatx80_mul(fp0
, fp2
,
2275 status
); /* ATANH(X) = SIGN(X) * (1/2) * LOG1P(Z) */
2277 float_raise(float_flag_inexact
, status
);
2286 floatx80
floatx80_etoxm1(floatx80 a
, float_status
*status
)
2292 int8_t user_rnd_mode
, user_rnd_prec
;
2294 int32_t compact
, n
, j
, m
, m1
;
2295 floatx80 fp0
, fp1
, fp2
, fp3
, l2
, sc
, onebysc
;
2297 aSig
= extractFloatx80Frac(a
);
2298 aExp
= extractFloatx80Exp(a
);
2299 aSign
= extractFloatx80Sign(a
);
2301 if (aExp
== 0x7FFF) {
2302 if ((uint64_t) (aSig
<< 1)) {
2303 return propagateFloatx80NaNOneArg(a
, status
);
2306 return packFloatx80(aSign
, one_exp
, one_sig
);
2308 return packFloatx80(0, floatx80_infinity
.high
,
2309 floatx80_infinity
.low
);
2312 if (aExp
== 0 && aSig
== 0) {
2313 return packFloatx80(aSign
, 0, 0);
2316 user_rnd_mode
= status
->float_rounding_mode
;
2317 user_rnd_prec
= status
->floatx80_rounding_precision
;
2318 status
->float_rounding_mode
= float_round_nearest_even
;
2319 status
->floatx80_rounding_precision
= 80;
2321 if (aExp
>= 0x3FFD) { /* |X| >= 1/4 */
2322 compact
= floatx80_make_compact(aExp
, aSig
);
2324 if (compact
<= 0x4004C215) { /* |X| <= 70 log2 */
2327 fp0
= floatx80_mul(fp0
, float32_to_floatx80(
2328 make_float32(0x42B8AA3B), status
),
2329 status
); /* 64/log2 * X */
2330 n
= floatx80_to_int32(fp0
, status
); /* int(64/log2*X) */
2331 fp0
= int32_to_floatx80(n
, status
);
2333 j
= n
& 0x3F; /* J = N mod 64 */
2334 m
= n
/ 64; /* NOTE: this is really arithmetic right shift by 6 */
2337 * arithmetic right shift is division and
2338 * round towards minus infinity
2343 /*m += 0x3FFF; // biased exponent of 2^(M) */
2344 /*m1 += 0x3FFF; // biased exponent of -2^(-M) */
2347 fp0
= floatx80_mul(fp0
, float32_to_floatx80(
2348 make_float32(0xBC317218), status
),
2349 status
); /* N * L1, L1 = lead(-log2/64) */
2350 l2
= packFloatx80(0, 0x3FDC, UINT64_C(0x82E308654361C4C6));
2351 fp2
= floatx80_mul(fp2
, l2
, status
); /* N * L2, L1+L2 = -log2/64 */
2352 fp0
= floatx80_add(fp0
, fp1
, status
); /* X + N*L1 */
2353 fp0
= floatx80_add(fp0
, fp2
, status
); /* R */
2355 fp1
= floatx80_mul(fp0
, fp0
, status
); /* S = R*R */
2356 fp2
= float32_to_floatx80(make_float32(0x3950097B),
2358 fp2
= floatx80_mul(fp2
, fp1
, status
); /* fp2 is S*A6 */
2359 fp3
= floatx80_mul(float32_to_floatx80(make_float32(0x3AB60B6A),
2360 status
), fp1
, status
); /* fp3 is S*A5 */
2361 fp2
= floatx80_add(fp2
, float64_to_floatx80(
2362 make_float64(0x3F81111111174385), status
),
2363 status
); /* fp2 IS A4+S*A6 */
2364 fp3
= floatx80_add(fp3
, float64_to_floatx80(
2365 make_float64(0x3FA5555555554F5A), status
),
2366 status
); /* fp3 is A3+S*A5 */
2367 fp2
= floatx80_mul(fp2
, fp1
, status
); /* fp2 IS S*(A4+S*A6) */
2368 fp3
= floatx80_mul(fp3
, fp1
, status
); /* fp3 IS S*(A3+S*A5) */
2369 fp2
= floatx80_add(fp2
, float64_to_floatx80(
2370 make_float64(0x3FC5555555555555), status
),
2371 status
); /* fp2 IS A2+S*(A4+S*A6) */
2372 fp3
= floatx80_add(fp3
, float32_to_floatx80(
2373 make_float32(0x3F000000), status
),
2374 status
); /* fp3 IS A1+S*(A3+S*A5) */
2375 fp2
= floatx80_mul(fp2
, fp1
,
2376 status
); /* fp2 IS S*(A2+S*(A4+S*A6)) */
2377 fp1
= floatx80_mul(fp1
, fp3
,
2378 status
); /* fp1 IS S*(A1+S*(A3+S*A5)) */
2379 fp2
= floatx80_mul(fp2
, fp0
,
2380 status
); /* fp2 IS R*S*(A2+S*(A4+S*A6)) */
2381 fp0
= floatx80_add(fp0
, fp1
,
2382 status
); /* fp0 IS R+S*(A1+S*(A3+S*A5)) */
2383 fp0
= floatx80_add(fp0
, fp2
, status
); /* fp0 IS EXP(R) - 1 */
2385 fp0
= floatx80_mul(fp0
, exp_tbl
[j
],
2386 status
); /* 2^(J/64)*(Exp(R)-1) */
2389 fp1
= float32_to_floatx80(exp_tbl2
[j
], status
);
2390 onebysc
= packFloatx80(1, m1
+ 0x3FFF, one_sig
); /* -2^(-M) */
2391 fp1
= floatx80_add(fp1
, onebysc
, status
);
2392 fp0
= floatx80_add(fp0
, fp1
, status
);
2393 fp0
= floatx80_add(fp0
, exp_tbl
[j
], status
);
2394 } else if (m
< -3) {
2395 fp0
= floatx80_add(fp0
, float32_to_floatx80(exp_tbl2
[j
],
2397 fp0
= floatx80_add(fp0
, exp_tbl
[j
], status
);
2398 onebysc
= packFloatx80(1, m1
+ 0x3FFF, one_sig
); /* -2^(-M) */
2399 fp0
= floatx80_add(fp0
, onebysc
, status
);
2400 } else { /* -3 <= m <= 63 */
2402 fp0
= floatx80_add(fp0
, float32_to_floatx80(exp_tbl2
[j
],
2404 onebysc
= packFloatx80(1, m1
+ 0x3FFF, one_sig
); /* -2^(-M) */
2405 fp1
= floatx80_add(fp1
, onebysc
, status
);
2406 fp0
= floatx80_add(fp0
, fp1
, status
);
2409 sc
= packFloatx80(0, m
+ 0x3FFF, one_sig
);
2411 status
->float_rounding_mode
= user_rnd_mode
;
2412 status
->floatx80_rounding_precision
= user_rnd_prec
;
2414 a
= floatx80_mul(fp0
, sc
, status
);
2416 float_raise(float_flag_inexact
, status
);
2419 } else { /* |X| > 70 log2 */
2421 fp0
= float32_to_floatx80(make_float32(0xBF800000),
2424 status
->float_rounding_mode
= user_rnd_mode
;
2425 status
->floatx80_rounding_precision
= user_rnd_prec
;
2427 a
= floatx80_add(fp0
, float32_to_floatx80(
2428 make_float32(0x00800000), status
),
2429 status
); /* -1 + 2^(-126) */
2431 float_raise(float_flag_inexact
, status
);
2435 status
->float_rounding_mode
= user_rnd_mode
;
2436 status
->floatx80_rounding_precision
= user_rnd_prec
;
2438 return floatx80_etox(a
, status
);
2441 } else { /* |X| < 1/4 */
2442 if (aExp
>= 0x3FBE) {
2444 fp0
= floatx80_mul(fp0
, fp0
, status
); /* S = X*X */
2445 fp1
= float32_to_floatx80(make_float32(0x2F30CAA8),
2447 fp1
= floatx80_mul(fp1
, fp0
, status
); /* S * B12 */
2448 fp2
= float32_to_floatx80(make_float32(0x310F8290),
2450 fp1
= floatx80_add(fp1
, float32_to_floatx80(
2451 make_float32(0x32D73220), status
),
2453 fp2
= floatx80_mul(fp2
, fp0
, status
);
2454 fp1
= floatx80_mul(fp1
, fp0
, status
);
2455 fp2
= floatx80_add(fp2
, float32_to_floatx80(
2456 make_float32(0x3493F281), status
),
2458 fp1
= floatx80_add(fp1
, float64_to_floatx80(
2459 make_float64(0x3EC71DE3A5774682), status
),
2461 fp2
= floatx80_mul(fp2
, fp0
, status
);
2462 fp1
= floatx80_mul(fp1
, fp0
, status
);
2463 fp2
= floatx80_add(fp2
, float64_to_floatx80(
2464 make_float64(0x3EFA01A019D7CB68), status
),
2466 fp1
= floatx80_add(fp1
, float64_to_floatx80(
2467 make_float64(0x3F2A01A01A019DF3), status
),
2469 fp2
= floatx80_mul(fp2
, fp0
, status
);
2470 fp1
= floatx80_mul(fp1
, fp0
, status
);
2471 fp2
= floatx80_add(fp2
, float64_to_floatx80(
2472 make_float64(0x3F56C16C16C170E2), status
),
2474 fp1
= floatx80_add(fp1
, float64_to_floatx80(
2475 make_float64(0x3F81111111111111), status
),
2477 fp2
= floatx80_mul(fp2
, fp0
, status
);
2478 fp1
= floatx80_mul(fp1
, fp0
, status
);
2479 fp2
= floatx80_add(fp2
, float64_to_floatx80(
2480 make_float64(0x3FA5555555555555), status
),
2482 fp3
= packFloatx80(0, 0x3FFC, UINT64_C(0xAAAAAAAAAAAAAAAB));
2483 fp1
= floatx80_add(fp1
, fp3
, status
); /* B2 */
2484 fp2
= floatx80_mul(fp2
, fp0
, status
);
2485 fp1
= floatx80_mul(fp1
, fp0
, status
);
2487 fp2
= floatx80_mul(fp2
, fp0
, status
);
2488 fp1
= floatx80_mul(fp1
, a
, status
);
2490 fp0
= floatx80_mul(fp0
, float32_to_floatx80(
2491 make_float32(0x3F000000), status
),
2493 fp1
= floatx80_add(fp1
, fp2
, status
); /* Q */
2494 fp0
= floatx80_add(fp0
, fp1
, status
); /* S*B1+Q */
2496 status
->float_rounding_mode
= user_rnd_mode
;
2497 status
->floatx80_rounding_precision
= user_rnd_prec
;
2499 a
= floatx80_add(fp0
, a
, status
);
2501 float_raise(float_flag_inexact
, status
);
2504 } else { /* |X| < 2^(-65) */
2505 sc
= packFloatx80(1, 1, one_sig
);
2508 if (aExp
< 0x0033) { /* |X| < 2^(-16382) */
2509 fp0
= floatx80_mul(fp0
, float64_to_floatx80(
2510 make_float64(0x48B0000000000000), status
),
2512 fp0
= floatx80_add(fp0
, sc
, status
);
2514 status
->float_rounding_mode
= user_rnd_mode
;
2515 status
->floatx80_rounding_precision
= user_rnd_prec
;
2517 a
= floatx80_mul(fp0
, float64_to_floatx80(
2518 make_float64(0x3730000000000000), status
),
2521 status
->float_rounding_mode
= user_rnd_mode
;
2522 status
->floatx80_rounding_precision
= user_rnd_prec
;
2524 a
= floatx80_add(fp0
, sc
, status
);
2527 float_raise(float_flag_inexact
, status
);
2535 * Hyperbolic tangent
2538 floatx80
floatx80_tanh(floatx80 a
, float_status
*status
)
2542 uint64_t aSig
, vSig
;
2544 int8_t user_rnd_mode
, user_rnd_prec
;
2550 aSig
= extractFloatx80Frac(a
);
2551 aExp
= extractFloatx80Exp(a
);
2552 aSign
= extractFloatx80Sign(a
);
2554 if (aExp
== 0x7FFF) {
2555 if ((uint64_t) (aSig
<< 1)) {
2556 return propagateFloatx80NaNOneArg(a
, status
);
2558 return packFloatx80(aSign
, one_exp
, one_sig
);
2561 if (aExp
== 0 && aSig
== 0) {
2562 return packFloatx80(aSign
, 0, 0);
2565 user_rnd_mode
= status
->float_rounding_mode
;
2566 user_rnd_prec
= status
->floatx80_rounding_precision
;
2567 status
->float_rounding_mode
= float_round_nearest_even
;
2568 status
->floatx80_rounding_precision
= 80;
2570 compact
= floatx80_make_compact(aExp
, aSig
);
2572 if (compact
< 0x3FD78000 || compact
> 0x3FFFDDCE) {
2574 if (compact
< 0x3FFF8000) {
2576 status
->float_rounding_mode
= user_rnd_mode
;
2577 status
->floatx80_rounding_precision
= user_rnd_prec
;
2579 a
= floatx80_move(a
, status
);
2581 float_raise(float_flag_inexact
, status
);
2585 if (compact
> 0x40048AA1) {
2588 sign
|= aSign
? 0x80000000 : 0x00000000;
2589 fp0
= float32_to_floatx80(make_float32(sign
), status
);
2591 sign
^= 0x80800000; /* -SIGN(X)*EPS */
2593 status
->float_rounding_mode
= user_rnd_mode
;
2594 status
->floatx80_rounding_precision
= user_rnd_prec
;
2596 a
= floatx80_add(fp0
, float32_to_floatx80(make_float32(sign
),
2599 float_raise(float_flag_inexact
, status
);
2603 fp0
= packFloatx80(0, aExp
+ 1, aSig
); /* Y = 2|X| */
2604 fp0
= floatx80_etox(fp0
, status
); /* FP0 IS EXP(Y) */
2605 fp0
= floatx80_add(fp0
, float32_to_floatx80(
2606 make_float32(0x3F800000),
2607 status
), status
); /* EXP(Y)+1 */
2608 sign
= aSign
? 0x80000000 : 0x00000000;
2609 fp1
= floatx80_div(float32_to_floatx80(make_float32(
2610 sign
^ 0xC0000000), status
), fp0
,
2611 status
); /* -SIGN(X)*2 / [EXP(Y)+1] */
2612 fp0
= float32_to_floatx80(make_float32(sign
| 0x3F800000),
2615 status
->float_rounding_mode
= user_rnd_mode
;
2616 status
->floatx80_rounding_precision
= user_rnd_prec
;
2618 a
= floatx80_add(fp1
, fp0
, status
);
2620 float_raise(float_flag_inexact
, status
);
2625 } else { /* 2**(-40) < |X| < (5/2)LOG2 */
2626 fp0
= packFloatx80(0, aExp
+ 1, aSig
); /* Y = 2|X| */
2627 fp0
= floatx80_etoxm1(fp0
, status
); /* FP0 IS Z = EXPM1(Y) */
2628 fp1
= floatx80_add(fp0
, float32_to_floatx80(make_float32(0x40000000),
2632 vSign
= extractFloatx80Sign(fp1
);
2633 vExp
= extractFloatx80Exp(fp1
);
2634 vSig
= extractFloatx80Frac(fp1
);
2636 fp1
= packFloatx80(vSign
^ aSign
, vExp
, vSig
);
2638 status
->float_rounding_mode
= user_rnd_mode
;
2639 status
->floatx80_rounding_precision
= user_rnd_prec
;
2641 a
= floatx80_div(fp0
, fp1
, status
);
2643 float_raise(float_flag_inexact
, status
);
2653 floatx80
floatx80_sinh(floatx80 a
, float_status
*status
)
2659 int8_t user_rnd_mode
, user_rnd_prec
;
2662 floatx80 fp0
, fp1
, fp2
;
2665 aSig
= extractFloatx80Frac(a
);
2666 aExp
= extractFloatx80Exp(a
);
2667 aSign
= extractFloatx80Sign(a
);
2669 if (aExp
== 0x7FFF) {
2670 if ((uint64_t) (aSig
<< 1)) {
2671 return propagateFloatx80NaNOneArg(a
, status
);
2673 return packFloatx80(aSign
, floatx80_infinity
.high
,
2674 floatx80_infinity
.low
);
2677 if (aExp
== 0 && aSig
== 0) {
2678 return packFloatx80(aSign
, 0, 0);
2681 user_rnd_mode
= status
->float_rounding_mode
;
2682 user_rnd_prec
= status
->floatx80_rounding_precision
;
2683 status
->float_rounding_mode
= float_round_nearest_even
;
2684 status
->floatx80_rounding_precision
= 80;
2686 compact
= floatx80_make_compact(aExp
, aSig
);
2688 if (compact
> 0x400CB167) {
2690 if (compact
> 0x400CB2B3) {
2691 status
->float_rounding_mode
= user_rnd_mode
;
2692 status
->floatx80_rounding_precision
= user_rnd_prec
;
2694 return roundAndPackFloatx80(status
->floatx80_rounding_precision
,
2695 aSign
, 0x8000, aSig
, 0, status
);
2697 fp0
= floatx80_abs(a
); /* Y = |X| */
2698 fp0
= floatx80_sub(fp0
, float64_to_floatx80(
2699 make_float64(0x40C62D38D3D64634), status
),
2700 status
); /* (|X|-16381LOG2_LEAD) */
2701 fp0
= floatx80_sub(fp0
, float64_to_floatx80(
2702 make_float64(0x3D6F90AEB1E75CC7), status
),
2703 status
); /* |X| - 16381 LOG2, ACCURATE */
2704 fp0
= floatx80_etox(fp0
, status
);
2705 fp2
= packFloatx80(aSign
, 0x7FFB, one_sig
);
2707 status
->float_rounding_mode
= user_rnd_mode
;
2708 status
->floatx80_rounding_precision
= user_rnd_prec
;
2710 a
= floatx80_mul(fp0
, fp2
, status
);
2712 float_raise(float_flag_inexact
, status
);
2716 } else { /* |X| < 16380 LOG2 */
2717 fp0
= floatx80_abs(a
); /* Y = |X| */
2718 fp0
= floatx80_etoxm1(fp0
, status
); /* FP0 IS Z = EXPM1(Y) */
2719 fp1
= floatx80_add(fp0
, float32_to_floatx80(make_float32(0x3F800000),
2720 status
), status
); /* 1+Z */
2722 fp0
= floatx80_div(fp0
, fp1
, status
); /* Z/(1+Z) */
2723 fp0
= floatx80_add(fp0
, fp2
, status
);
2725 fact
= packFloat32(aSign
, 0x7E, 0);
2727 status
->float_rounding_mode
= user_rnd_mode
;
2728 status
->floatx80_rounding_precision
= user_rnd_prec
;
2730 a
= floatx80_mul(fp0
, float32_to_floatx80(fact
, status
), status
);
2732 float_raise(float_flag_inexact
, status
);
2742 floatx80
floatx80_cosh(floatx80 a
, float_status
*status
)
2747 int8_t user_rnd_mode
, user_rnd_prec
;
2752 aSig
= extractFloatx80Frac(a
);
2753 aExp
= extractFloatx80Exp(a
);
2755 if (aExp
== 0x7FFF) {
2756 if ((uint64_t) (aSig
<< 1)) {
2757 return propagateFloatx80NaNOneArg(a
, status
);
2759 return packFloatx80(0, floatx80_infinity
.high
,
2760 floatx80_infinity
.low
);
2763 if (aExp
== 0 && aSig
== 0) {
2764 return packFloatx80(0, one_exp
, one_sig
);
2767 user_rnd_mode
= status
->float_rounding_mode
;
2768 user_rnd_prec
= status
->floatx80_rounding_precision
;
2769 status
->float_rounding_mode
= float_round_nearest_even
;
2770 status
->floatx80_rounding_precision
= 80;
2772 compact
= floatx80_make_compact(aExp
, aSig
);
2774 if (compact
> 0x400CB167) {
2775 if (compact
> 0x400CB2B3) {
2776 status
->float_rounding_mode
= user_rnd_mode
;
2777 status
->floatx80_rounding_precision
= user_rnd_prec
;
2778 return roundAndPackFloatx80(status
->floatx80_rounding_precision
, 0,
2779 0x8000, one_sig
, 0, status
);
2781 fp0
= packFloatx80(0, aExp
, aSig
);
2782 fp0
= floatx80_sub(fp0
, float64_to_floatx80(
2783 make_float64(0x40C62D38D3D64634), status
),
2785 fp0
= floatx80_sub(fp0
, float64_to_floatx80(
2786 make_float64(0x3D6F90AEB1E75CC7), status
),
2788 fp0
= floatx80_etox(fp0
, status
);
2789 fp1
= packFloatx80(0, 0x7FFB, one_sig
);
2791 status
->float_rounding_mode
= user_rnd_mode
;
2792 status
->floatx80_rounding_precision
= user_rnd_prec
;
2794 a
= floatx80_mul(fp0
, fp1
, status
);
2796 float_raise(float_flag_inexact
, status
);
2802 fp0
= packFloatx80(0, aExp
, aSig
); /* |X| */
2803 fp0
= floatx80_etox(fp0
, status
); /* EXP(|X|) */
2804 fp0
= floatx80_mul(fp0
, float32_to_floatx80(make_float32(0x3F000000),
2805 status
), status
); /* (1/2)*EXP(|X|) */
2806 fp1
= float32_to_floatx80(make_float32(0x3E800000), status
); /* 1/4 */
2807 fp1
= floatx80_div(fp1
, fp0
, status
); /* 1/(2*EXP(|X|)) */
2809 status
->float_rounding_mode
= user_rnd_mode
;
2810 status
->floatx80_rounding_precision
= user_rnd_prec
;
2812 a
= floatx80_add(fp0
, fp1
, status
);
2814 float_raise(float_flag_inexact
, status
);