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