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