Annotation of previous/src/softfloat/softfloat_fpsp.c, revision 1.1.1.2

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: 
1.1.1.2 ! root       36: static int32 floatx80_make_compact(int32 aExp, bits64 aSig)
1.1       root       37: {
                     38:     return (aExp<<16)|(aSig>>48);
                     39: }
                     40: 
                     41: 
                     42: /*----------------------------------------------------------------------------
                     43:  | Arc cosine
                     44:  *----------------------------------------------------------------------------*/
                     45: 
1.1.1.2 ! root       46: floatx80 floatx80_acos(floatx80 a, float_ctrl* c)
1.1       root       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)) {
1.1.1.2 ! root       62:         return propagateFloatx80NaNOneArg(a, c);
1.1       root       63:     }
                     64:     if (aExp == 0 && aSig == 0) {
1.1.1.2 ! root       65:         float_raise(float_flag_inexact, c);
        !            66:         return roundAndPackFloatx80(get_float_rounding_precision(c), 0, piby2_exp, pi_sig, 0, c);
1.1       root       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);
1.1.1.2 ! root       75:                 float_raise(float_flag_inexact, c);
        !            76:                 return floatx80_move(a, c);
1.1       root       77:             } else { // X == +1
                     78:                 return packFloatx80(0, 0, 0);
                     79:             }
                     80:         } else { // |X| > 1
1.1.1.2 ! root       81:             float_raise(float_flag_invalid, c);
1.1       root       82:             a.low = floatx80_default_nan_low;
                     83:             a.high = floatx80_default_nan_high;
                     84:             return a;
                     85:         }
                     86:     } // |X| < 1
                     87:     
1.1.1.2 ! root       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);
1.1       root       92:     
                     93:     one = packFloatx80(0, one_exp, one_sig);
                     94:     fp0 = a;
                     95:     
1.1.1.2 ! root       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)))
1.1       root      101:     
1.1.1.2 ! root      102:     set_float_rounding_mode(user_rnd_mode, c);
        !           103:     set_float_rounding_precision(user_rnd_prec, c);
1.1       root      104:     
1.1.1.2 ! root      105:     a = floatx80_add(fp0, fp0, c);     // 2 * ATAN(SQRT((1-X)/(1+X)))
1.1       root      106:     
1.1.1.2 ! root      107:     float_raise(float_flag_inexact, c);
1.1       root      108:     
                    109:     return a;
                    110: }
                    111: 
                    112: /*----------------------------------------------------------------------------
                    113:  | Arc sine
                    114:  *----------------------------------------------------------------------------*/
                    115: 
1.1.1.2 ! root      116: floatx80 floatx80_asin(floatx80 a, float_ctrl* c)
1.1       root      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)) {
1.1.1.2 ! root      132:         return propagateFloatx80NaNOneArg(a, c);
1.1       root      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
1.1.1.2 ! root      143:             float_raise(float_flag_inexact, c);
1.1       root      144:             a = packFloatx80(aSign, piby2_exp, pi_sig);
1.1.1.2 ! root      145:             return floatx80_move(a, c);
1.1       root      146:         } else { // |X| > 1
1.1.1.2 ! root      147:             float_raise(float_flag_invalid, c);
1.1       root      148:             a.low = floatx80_default_nan_low;
                    149:             a.high = floatx80_default_nan_high;
                    150:             return a;
                    151:         }
                    152: 
                    153:     } // |X| < 1
                    154:     
1.1.1.2 ! root      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);
1.1       root      159:     
                    160:     one = packFloatx80(0, one_exp, one_sig);
                    161:     fp0 = a;
                    162: 
1.1.1.2 ! root      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))
1.1       root      168:     
1.1.1.2 ! root      169:     set_float_rounding_mode(user_rnd_mode, c);
        !           170:     set_float_rounding_precision(user_rnd_prec, c);
1.1       root      171:     
1.1.1.2 ! root      172:     a = floatx80_atan(fp0, c);         // ATAN(X/SQRT((1+X)*(1-X)))
1.1       root      173:     
1.1.1.2 ! root      174:     float_raise(float_flag_inexact, c);
1.1       root      175: 
                    176:     return a;
                    177: }
                    178: 
                    179: /*----------------------------------------------------------------------------
                    180:  | Arc tangent
                    181:  *----------------------------------------------------------------------------*/
                    182: 
1.1.1.2 ! root      183: floatx80 floatx80_atan(floatx80 a, float_ctrl* c)
1.1       root      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) {
1.1.1.2 ! root      199:         if ((bits64) (aSig<<1)) return propagateFloatx80NaNOneArg(a, c);
1.1       root      200:         a = packFloatx80(aSign, piby2_exp, pi_sig);
1.1.1.2 ! root      201:         float_raise(float_flag_inexact, c);
        !           202:         return floatx80_move(a, c);
1.1       root      203:     }
                    204:     
                    205:     if (aExp == 0 && aSig == 0) {
                    206:         return packFloatx80(aSign, 0, 0);
                    207:     }
                    208:     
                    209:     compact = floatx80_make_compact(aExp, aSig);
                    210:     
1.1.1.2 ! root      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);
1.1       root      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:                 
1.1.1.2 ! root      222:                 set_float_rounding_mode(user_rnd_mode, c);
        !           223:                 set_float_rounding_precision(user_rnd_prec, c);
1.1       root      224:                 
1.1.1.2 ! root      225:                 a = floatx80_sub(fp0, fp1, c);
1.1       root      226:                 
1.1.1.2 ! root      227:                 float_raise(float_flag_inexact, c);
1.1       root      228:                 
                    229:                 return a;
                    230:             } else {
                    231:                 fp0 = a;
                    232:                 fp1 = packFloatx80(1, one_exp, one_sig); // -1
1.1.1.2 ! root      233:                 fp1 = floatx80_div(fp1, fp0, c); // X' = -1/X
1.1       root      234:                 xsave = fp1;
1.1.1.2 ! root      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);
1.1       root      250:                 fp1 = packFloatx80(aSign, piby2_exp, pi_sig);
                    251:                 
1.1.1.2 ! root      252:                 set_float_rounding_mode(user_rnd_mode, c);
        !           253:                 set_float_rounding_precision(user_rnd_prec, c);
1.1       root      254: 
1.1.1.2 ! root      255:                 a = floatx80_add(fp0, fp1, c);
1.1       root      256:                 
1.1.1.2 ! root      257:                 float_raise(float_flag_inexact, c);
1.1       root      258:                 
                    259:                 return a;
                    260:             }
                    261:         } else { // |X| < 1/16
                    262:             if (compact < 0x3FD78000) { // |X| < 2^(-40)
1.1.1.2 ! root      263:                 set_float_rounding_mode(user_rnd_mode, c);
        !           264:                 set_float_rounding_precision(user_rnd_prec, c);
1.1       root      265:                 
1.1.1.2 ! root      266:                 a = floatx80_move(a, c);
1.1       root      267:                 
1.1.1.2 ! root      268:                 float_raise(float_flag_inexact, c);
1.1       root      269:                 
                    270:                 return a;
                    271:             } else {
                    272:                 fp0 = a;
                    273:                 xsave = a;
1.1.1.2 ! root      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))])
1.1       root      290:                 
1.1.1.2 ! root      291:                 set_float_rounding_mode(user_rnd_mode, c);
        !           292:                 set_float_rounding_precision(user_rnd_prec, c);
1.1       root      293:                 
1.1.1.2 ! root      294:                 a = floatx80_add(fp0, xsave, c);
1.1       root      295:                 
1.1.1.2 ! root      296:                 float_raise(float_flag_inexact, c);
1.1       root      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
1.1.1.2 ! root      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)
1.1       root      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:         
1.1.1.2 ! root      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)
1.1       root      334:         
1.1.1.2 ! root      335:         set_float_rounding_mode(user_rnd_mode, c);
        !           336:         set_float_rounding_precision(user_rnd_prec, c);
1.1       root      337:         
1.1.1.2 ! root      338:         a = floatx80_add(fp0, fp3, c); // ATAN(X)
1.1       root      339:         
1.1.1.2 ! root      340:         float_raise(float_flag_inexact, c);
1.1       root      341:         
                    342:         return a;
                    343:     }
                    344: }
                    345: 
                    346: /*----------------------------------------------------------------------------
                    347:  | Hyperbolic arc tangent
                    348:  *----------------------------------------------------------------------------*/
                    349: 
1.1.1.2 ! root      350: floatx80 floatx80_atanh(floatx80 a, float_ctrl* c)
1.1       root      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)) {
1.1.1.2 ! root      366:         return propagateFloatx80NaNOneArg(a, c);
1.1       root      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
1.1.1.2 ! root      377:             float_raise(float_flag_divbyzero, c);
1.1       root      378:             return packFloatx80(aSign, 0x7FFF, floatx80_default_infinity_low);
                    379:         } else { // |X| > 1
1.1.1.2 ! root      380:             float_raise(float_flag_invalid, c);
1.1       root      381:             a.low = floatx80_default_nan_low;
                    382:             a.high = floatx80_default_nan_high;
                    383:             return a;
                    384:         }
                    385:     } // |X| < 1
                    386:     
1.1.1.2 ! root      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);
1.1       root      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
1.1.1.2 ! root      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)
1.1       root      400:     
1.1.1.2 ! root      401:     set_float_rounding_mode(user_rnd_mode, c);
        !           402:     set_float_rounding_precision(user_rnd_prec, c);
1.1       root      403:     
1.1.1.2 ! root      404:     a = floatx80_mul(fp0, fp2, c); // ATANH(X) = SIGN(X) * (1/2) * LOG1P(Z)
1.1       root      405:     
1.1.1.2 ! root      406:     float_raise(float_flag_inexact, c);
1.1       root      407:     
                    408:     return a;
                    409: }
                    410: 
                    411: /*----------------------------------------------------------------------------
                    412:  | Cosine
                    413:  *----------------------------------------------------------------------------*/
                    414: 
1.1.1.2 ! root      415: floatx80 floatx80_cos(floatx80 a, float_ctrl* c)
1.1       root      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) {
1.1.1.2 ! root      433:         if ((bits64) (aSig<<1)) return propagateFloatx80NaNOneArg(a, c);
        !           434:         float_raise(float_flag_invalid, c);
1.1       root      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:     
1.1.1.2 ! root      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);
1.1       root      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));
1.1.1.2 ! root      462:                 fp0 = floatx80_add(fp0, twopi1, c);
1.1       root      463:                 fp1 = fp0;
1.1.1.2 ! root      464:                 fp0 = floatx80_add(fp0, twopi2, c);
        !           465:                 fp1 = floatx80_sub(fp1, fp0, c);
        !           466:                 fp1 = floatx80_add(fp1, twopi2, c);
1.1       root      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:             
1.1.1.2 ! root      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
1.1       root      495:             fp3 = fp0; // FP3 is A
1.1.1.2 ! root      496:             fp1 = floatx80_sub(fp1, fp4, c); // FP1 is a := r - p
        !           497:             fp0 = floatx80_add(fp0, fp1, c); // FP0 is R := A+a
1.1       root      498:             
                    499:             if (endflag > 0) {
1.1.1.2 ! root      500:                 n = floatx80_to_int32(fp2, c);
1.1       root      501:                 goto sincont;
                    502:             }
1.1.1.2 ! root      503:             fp3 = floatx80_sub(fp3, fp0, c); // A-R
        !           504:             fp1 = floatx80_add(fp1, fp3, c); // FP1 is r := (A-R)+a
1.1       root      505:             goto loop;
                    506:         } else {
                    507:             // SINSM
1.1.1.2 ! root      508:             fp0 = float32_to_floatx80(0x3F800000, c); // 1
1.1       root      509:             
1.1.1.2 ! root      510:             set_float_rounding_mode(user_rnd_mode, c);
        !           511:             set_float_rounding_precision(user_rnd_prec, c);
1.1       root      512:             
                    513:             if (adjn) {
                    514:                 // COSTINY
1.1.1.2 ! root      515:                 a = floatx80_sub(fp0, float32_to_floatx80(0x00800000, c), c);
1.1       root      516:             } else {
                    517:                 // SINTINY
1.1.1.2 ! root      518:                 a = floatx80_move(a, c);
1.1       root      519:             }
1.1.1.2 ! root      520:             float_raise(float_flag_inexact, c);
1.1       root      521:             
                    522:             return a;
                    523:         }
                    524:     } else {
1.1.1.2 ! root      525:         fp1 = floatx80_mul(fp0, float64_to_floatx80(LIT64(0x3FE45F306DC9C883), c), c); // X*2/PI
1.1       root      526:         
1.1.1.2 ! root      527:         n = floatx80_to_int32(fp1, c);
1.1       root      528:         j = 32 + n;
                    529:         
1.1.1.2 ! root      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
1.1       root      532:         
                    533:     sincont:
                    534:         if ((n + adjn) & 1) {
                    535:             // COSPOLY
1.1.1.2 ! root      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
1.1       root      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:             
1.1.1.2 ! root      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)
1.1       root      560:             fp4 = packFloatx80(1, 0x3FF5, LIT64(0xB60B60B60B61D438));
1.1.1.2 ! root      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))
1.1       root      564:             fp4 = packFloatx80(0, 0x3FFA, LIT64(0xAAAAAAAAAAAAAB5E));
1.1.1.2 ! root      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)))]
1.1       root      569:             
                    570:             x = packFloatx80(xSign, xExp, xSig);
1.1.1.2 ! root      571:             fp0 = floatx80_mul(fp0, x, c);
1.1       root      572:             
1.1.1.2 ! root      573:             set_float_rounding_mode(user_rnd_mode, c);
        !           574:             set_float_rounding_precision(user_rnd_prec, c);
1.1       root      575:             
1.1.1.2 ! root      576:             a = floatx80_add(fp0, float32_to_floatx80(posneg1, c), c);
1.1       root      577:             
1.1.1.2 ! root      578:             float_raise(float_flag_inexact, c);
1.1       root      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:             
1.1.1.2 ! root      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)
1.1       root      600:             fp4 = packFloatx80(0, 0x3FF8, LIT64(0x88888888888859AF));
1.1.1.2 ! root      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))
1.1       root      604:             fp4 = packFloatx80(1, 0x3FFC, LIT64(0xAAAAAAAAAAAAAA99));
1.1.1.2 ! root      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))]
1.1       root      607:             
                    608:             x = packFloatx80(xSign, xExp, xSig);
1.1.1.2 ! root      609:             fp0 = floatx80_mul(fp0, x, c); // R'*S
        !           610:             fp0 = floatx80_mul(fp0, fp1, c); // SIN(R')-R'
1.1       root      611:             
1.1.1.2 ! root      612:             set_float_rounding_mode(user_rnd_mode, c);
        !           613:             set_float_rounding_precision(user_rnd_prec, c);
1.1       root      614:             
1.1.1.2 ! root      615:             a = floatx80_add(fp0, x, c);
1.1       root      616:             
1.1.1.2 ! root      617:             float_raise(float_flag_inexact, c);
1.1       root      618:             
                    619:             return a;
                    620:         }
                    621:     }
                    622: }
                    623: 
                    624: /*----------------------------------------------------------------------------
                    625:  | Hyperbolic cosine
                    626:  *----------------------------------------------------------------------------*/
                    627: 
1.1.1.2 ! root      628: floatx80 floatx80_cosh(floatx80 a, float_ctrl* c)
1.1       root      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) {
1.1.1.2 ! root      642:         if ((bits64) (aSig<<1)) return propagateFloatx80NaNOneArg(a, c);
1.1       root      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:     
1.1.1.2 ! root      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);
1.1       root      654:     
                    655:     compact = floatx80_make_compact(aExp, aSig);
                    656:     
                    657:     if (compact > 0x400CB167) {
                    658:         if (compact > 0x400CB2B3) {
1.1.1.2 ! root      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);
1.1       root      662:         } else {
                    663:             fp0 = packFloatx80(0, aExp, aSig);
1.1.1.2 ! root      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);
1.1       root      667:             fp1 = packFloatx80(0, 0x7FFB, one_sig);
                    668:             
1.1.1.2 ! root      669:             set_float_rounding_mode(user_rnd_mode, c);
        !           670:             set_float_rounding_precision(user_rnd_prec, c);
1.1       root      671: 
1.1.1.2 ! root      672:             a = floatx80_mul(fp0, fp1, c);
1.1       root      673:             
1.1.1.2 ! root      674:             float_raise(float_flag_inexact, c);
1.1       root      675:             
                    676:             return a;
                    677:         }
                    678:     }
                    679:     
                    680:     fp0 = packFloatx80(0, aExp, aSig); // |X|
1.1.1.2 ! root      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|))
1.1       root      685:     
1.1.1.2 ! root      686:     set_float_rounding_mode(user_rnd_mode, c);
        !           687:     set_float_rounding_precision(user_rnd_prec, c);
1.1       root      688:     
1.1.1.2 ! root      689:     a = floatx80_add(fp0, fp1, c);
1.1       root      690:     
1.1.1.2 ! root      691:     float_raise(float_flag_inexact, c);
1.1       root      692:     
                    693:     return a;
                    694: }
                    695: 
                    696: /*----------------------------------------------------------------------------
                    697:  | e to x
                    698:  *----------------------------------------------------------------------------*/
                    699: 
1.1.1.2 ! root      700: floatx80 floatx80_etox(floatx80 a, float_ctrl* c)
1.1       root      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) {
1.1.1.2 ! root      717:         if ((bits64) (aSig<<1)) return propagateFloatx80NaNOneArg(a, c);
1.1       root      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:     
1.1.1.2 ! root      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);
1.1       root      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;
1.1.1.2 ! root      739:             fp0 = floatx80_mul(fp0, float32_to_floatx80(0x42B8AA3B, c), c); // 64/log2 * X
1.1       root      740:             adjflag = 0;
1.1.1.2 ! root      741:             n = floatx80_to_int32(fp0, c); // int(64/log2*X)
1.1       root      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
1.1.1.2 ! root      753:             fp0 = floatx80_mul(fp0, float32_to_floatx80(0xBC317218, c), c); // N * L1, L1 = lead(-log2/64)
1.1       root      754:             l2 = packFloatx80(0, 0x3FDC, LIT64(0x82E308654361C4C6));
1.1.1.2 ! root      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
1.1       root      772:             
                    773:             fp1 = exp_tbl[j];
1.1.1.2 ! root      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)
1.1       root      777:             
                    778:             scale = packFloatx80(0, m, one_sig);
                    779:             if (adjflag) {
                    780:                 adjscale = packFloatx80(0, m1, one_sig);
1.1.1.2 ! root      781:                 fp0 = floatx80_mul(fp0, adjscale, c);
1.1       root      782:             }
                    783:             
1.1.1.2 ! root      784:             set_float_rounding_mode(user_rnd_mode, c);
        !           785:             set_float_rounding_precision(user_rnd_prec, c);
1.1       root      786:             
1.1.1.2 ! root      787:             a = floatx80_mul(fp0, scale, c);
1.1       root      788:             
1.1.1.2 ! root      789:             float_raise(float_flag_inexact, c);
1.1       root      790:             
                    791:             return a;
                    792:         } else { // |X| >= 16380 log2
                    793:             if (compact > 0x400CB27C) { // |X| >= 16480 log2
1.1.1.2 ! root      794:                 set_float_rounding_mode(user_rnd_mode, c);
        !           795:                 set_float_rounding_precision(user_rnd_prec, c);
1.1       root      796:                 if (aSign) {
1.1.1.2 ! root      797:                     a = roundAndPackFloatx80(get_float_rounding_precision(c), 0, -0x1000, aSig, 0, c);
1.1       root      798:                 } else {
1.1.1.2 ! root      799:                     a = roundAndPackFloatx80(get_float_rounding_precision(c), 0, 0x8000, aSig, 0, c);
1.1       root      800:                 }
1.1.1.2 ! root      801:                 float_raise(float_flag_inexact, c);
1.1       root      802:                 
                    803:                 return a;
                    804:             } else {
                    805:                 fp0 = a;
                    806:                 fp1 = a;
1.1.1.2 ! root      807:                 fp0 = floatx80_mul(fp0, float32_to_floatx80(0x42B8AA3B, c), c); // 64/log2 * X
1.1       root      808:                 adjflag = 1;
1.1.1.2 ! root      809:                 n = floatx80_to_int32(fp0, c); // int(64/log2*X)
1.1       root      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)
1.1.1.2 ! root      829:         set_float_rounding_mode(user_rnd_mode, c);
        !           830:         set_float_rounding_precision(user_rnd_prec, c);
1.1       root      831:         
1.1.1.2 ! root      832:         a = floatx80_add(a, float32_to_floatx80(0x3F800000, c), c); // 1 + X
1.1       root      833:         
1.1.1.2 ! root      834:         float_raise(float_flag_inexact, c);
1.1       root      835:         
                    836:         return a;
                    837:     }
                    838: }
                    839: 
                    840: /*----------------------------------------------------------------------------
                    841:  | e to x minus 1
                    842:  *----------------------------------------------------------------------------*/
                    843: 
1.1.1.2 ! root      844: floatx80 floatx80_etoxm1(floatx80 a, float_ctrl* c)
1.1       root      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) {
1.1.1.2 ! root      860:         if ((bits64) (aSig<<1)) return propagateFloatx80NaNOneArg(a, c);
1.1       root      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:     
1.1.1.2 ! root      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);
1.1       root      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;
1.1.1.2 ! root      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)
1.1       root      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
1.1.1.2 ! root      894:             fp0 = floatx80_mul(fp0, float32_to_floatx80(0xBC317218, c), c); // N * L1, L1 = lead(-log2/64)
1.1       root      895:             l2 = packFloatx80(0, 0x3FDC, LIT64(0x82E308654361C4C6));
1.1.1.2 ! root      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
1.1       root      915:             
1.1.1.2 ! root      916:             fp0 = floatx80_mul(fp0, exp_tbl[j], c); // 2^(J/64)*(Exp(R)-1)
1.1       root      917:             
                    918:             if (m >= 64) {
1.1.1.2 ! root      919:                 fp1 = float32_to_floatx80(exp_tbl2[j], c);
1.1       root      920:                 onebysc = packFloatx80(1, m1 + 0x3FFF, one_sig); // -2^(-M)
1.1.1.2 ! root      921:                 fp1 = floatx80_add(fp1, onebysc, c);
        !           922:                 fp0 = floatx80_add(fp0, fp1, c);
        !           923:                 fp0 = floatx80_add(fp0, exp_tbl[j], c);
1.1       root      924:             } else if (m < -3) {
1.1.1.2 ! root      925:                 fp0 = floatx80_add(fp0, float32_to_floatx80(exp_tbl2[j], c), c);
        !           926:                 fp0 = floatx80_add(fp0, exp_tbl[j], c);
1.1       root      927:                 onebysc = packFloatx80(1, m1 + 0x3FFF, one_sig); // -2^(-M)
1.1.1.2 ! root      928:                 fp0 = floatx80_add(fp0, onebysc, c);
1.1       root      929:             } else { // -3 <= m <= 63
                    930:                 fp1 = exp_tbl[j];
1.1.1.2 ! root      931:                 fp0 = floatx80_add(fp0, float32_to_floatx80(exp_tbl2[j], c), c);
1.1       root      932:                 onebysc = packFloatx80(1, m1 + 0x3FFF, one_sig); // -2^(-M)
1.1.1.2 ! root      933:                 fp1 = floatx80_add(fp1, onebysc, c);
        !           934:                 fp0 = floatx80_add(fp0, fp1, c);
1.1       root      935:             }
                    936:             
                    937:             sc = packFloatx80(0, m + 0x3FFF, one_sig);
                    938:             
1.1.1.2 ! root      939:             set_float_rounding_mode(user_rnd_mode, c);
        !           940:             set_float_rounding_precision(user_rnd_prec, c);
1.1       root      941:             
1.1.1.2 ! root      942:             a = floatx80_mul(fp0, sc, c);
1.1       root      943:             
1.1.1.2 ! root      944:             float_raise(float_flag_inexact, c);
1.1       root      945:             
                    946:             return a;
                    947:         } else { // |X| > 70 log2
                    948:             if (aSign) {
1.1.1.2 ! root      949:                 fp0 = float32_to_floatx80(0xBF800000, c); // -1
1.1       root      950:                 
1.1.1.2 ! root      951:                 set_float_rounding_mode(user_rnd_mode, c);
        !           952:                 set_float_rounding_precision(user_rnd_prec, c);
1.1       root      953:                 
1.1.1.2 ! root      954:                 a = floatx80_add(fp0, float32_to_floatx80(0x00800000, c), c); // -1 + 2^(-126)
1.1       root      955:                 
1.1.1.2 ! root      956:                 float_raise(float_flag_inexact, c);
1.1       root      957:                 
                    958:                 return a;
                    959:             } else {
1.1.1.2 ! root      960:                 set_float_rounding_mode(user_rnd_mode, c);
        !           961:                 set_float_rounding_precision(user_rnd_prec, c);
1.1       root      962:                 
1.1.1.2 ! root      963:                 return floatx80_etox(a, c);
1.1       root      964:             }
                    965:         }
                    966:     } else { // |X| < 1/4
                    967:         if (aExp >= 0x3FBE) {
                    968:             fp0 = a;
1.1.1.2 ! root      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
1.1       root      989:             fp3 = packFloatx80(0, 0x3FFC, LIT64(0xAAAAAAAAAAAAAAAB));
1.1.1.2 ! root      990:             fp1 = floatx80_add(fp1, fp3, c); // B2
        !           991:             fp2 = floatx80_mul(fp2, fp0, c);
        !           992:             fp1 = floatx80_mul(fp1, fp0, c);
1.1       root      993:             
1.1.1.2 ! root      994:             fp2 = floatx80_mul(fp2, fp0, c);
        !           995:             fp1 = floatx80_mul(fp1, a, c);
1.1       root      996:             
1.1.1.2 ! root      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
1.1       root     1000:             
1.1.1.2 ! root     1001:             set_float_rounding_mode(user_rnd_mode, c);
        !          1002:             set_float_rounding_precision(user_rnd_prec, c);
1.1       root     1003:             
1.1.1.2 ! root     1004:             a = floatx80_add(fp0, a, c);
1.1       root     1005:             
1.1.1.2 ! root     1006:             float_raise(float_flag_inexact, c);
1.1       root     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)
1.1.1.2 ! root     1014:                 fp0 = floatx80_mul(fp0, float64_to_floatx80(LIT64(0x48B0000000000000), c), c);
        !          1015:                 fp0 = floatx80_add(fp0, sc, c);
1.1       root     1016:                 
1.1.1.2 ! root     1017:                 set_float_rounding_mode(user_rnd_mode, c);
        !          1018:                 set_float_rounding_precision(user_rnd_prec, c);
1.1       root     1019: 
1.1.1.2 ! root     1020:                 a = floatx80_mul(fp0, float64_to_floatx80(LIT64(0x3730000000000000), c), c);
1.1       root     1021:             } else {
1.1.1.2 ! root     1022:                 set_float_rounding_mode(user_rnd_mode, c);
        !          1023:                 set_float_rounding_precision(user_rnd_prec, c);
1.1       root     1024:                 
1.1.1.2 ! root     1025:                 a = floatx80_add(fp0, sc, c);
1.1       root     1026:             }
                   1027:             
1.1.1.2 ! root     1028:             float_raise(float_flag_inexact, c);
1.1       root     1029:             
                   1030:             return a;
                   1031:         }
                   1032:     }
                   1033: }
                   1034: 
                   1035: /*----------------------------------------------------------------------------
                   1036:  | Log base 10
                   1037:  *----------------------------------------------------------------------------*/
                   1038: 
1.1.1.2 ! root     1039: floatx80 floatx80_log10(floatx80 a, float_ctrl* c)
1.1       root     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) {
1.1.1.2 ! root     1054:         if ((bits64) (aSig<<1)) propagateFloatx80NaNOneArg(a, c);
1.1       root     1055:         if (aSign == 0)
                   1056:             return packFloatx80(0, 0x7FFF, floatx80_default_infinity_low);
                   1057:     }
                   1058:     
                   1059:     if (aExp == 0 && aSig == 0) {
1.1.1.2 ! root     1060:         float_raise(float_flag_divbyzero, c);
1.1       root     1061:         return packFloatx80(1, 0x7FFF, floatx80_default_infinity_low);
                   1062:     }
                   1063:     
                   1064:     if (aSign) {
1.1.1.2 ! root     1065:         float_raise(float_flag_invalid, c);
1.1       root     1066:         a.low = floatx80_default_nan_low;
                   1067:         a.high = floatx80_default_nan_high;
                   1068:         return a;
                   1069:     }
                   1070:     
1.1.1.2 ! root     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);
1.1       root     1075:     
1.1.1.2 ! root     1076:     fp0 = floatx80_logn(a, c);
1.1       root     1077:     fp1 = packFloatx80(0, 0x3FFD, LIT64(0xDE5BD8A937287195)); // INV_L10
                   1078:     
1.1.1.2 ! root     1079:     set_float_rounding_mode(user_rnd_mode, c);
        !          1080:     set_float_rounding_precision(user_rnd_prec, c);
1.1       root     1081:     
1.1.1.2 ! root     1082:     a = floatx80_mul(fp0, fp1, c); // LOGN(X)*INV_L10
1.1       root     1083:     
1.1.1.2 ! root     1084:     float_raise(float_flag_inexact, c);
1.1       root     1085:     
                   1086:     return a;
                   1087: }
                   1088: 
                   1089: /*----------------------------------------------------------------------------
                   1090:  | Log base 2
                   1091:  *----------------------------------------------------------------------------*/
                   1092: 
1.1.1.2 ! root     1093: floatx80 floatx80_log2(floatx80 a, float_ctrl* c)
1.1       root     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) {
1.1.1.2 ! root     1108:         if ((bits64) (aSig<<1)) propagateFloatx80NaNOneArg(a, c);
1.1       root     1109:         if (aSign == 0)
                   1110:             return packFloatx80(0, 0x7FFF, floatx80_default_infinity_low);
                   1111:     }
                   1112:     
                   1113:     if (aExp == 0) {
                   1114:         if (aSig == 0) {
1.1.1.2 ! root     1115:             float_raise(float_flag_divbyzero, c);
1.1       root     1116:             return packFloatx80(1, 0x7FFF, floatx80_default_infinity_low);
                   1117:         }
                   1118:         normalizeFloatx80Subnormal(aSig, &aExp, &aSig);
                   1119:     }
                   1120:     
                   1121:     if (aSign) {
1.1.1.2 ! root     1122:         float_raise(float_flag_invalid, c);
1.1       root     1123:         a.low = floatx80_default_nan_low;
                   1124:         a.high = floatx80_default_nan_high;
                   1125:         return a;
                   1126:     }
                   1127:     
1.1.1.2 ! root     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);
1.1       root     1132:     
                   1133:     if (aSig == one_sig) { // X is 2^k
1.1.1.2 ! root     1134:         set_float_rounding_mode(user_rnd_mode, c);
        !          1135:         set_float_rounding_precision(user_rnd_prec, c);
1.1       root     1136:         
                   1137:         a = int32_to_floatx80(aExp-0x3FFF);
                   1138:     } else {
1.1.1.2 ! root     1139:         fp0 = floatx80_logn(a, c);
1.1       root     1140:         fp1 = packFloatx80(0, 0x3FFF, LIT64(0xB8AA3B295C17F0BC)); // INV_L2
                   1141:         
1.1.1.2 ! root     1142:         set_float_rounding_mode(user_rnd_mode, c);
        !          1143:         set_float_rounding_precision(user_rnd_prec, c);
1.1       root     1144:         
1.1.1.2 ! root     1145:         a = floatx80_mul(fp0, fp1, c); // LOGN(X)*INV_L2
1.1       root     1146:     }
                   1147:     
1.1.1.2 ! root     1148:     float_raise(float_flag_inexact, c);
1.1       root     1149:     
                   1150:     return a;
                   1151: }
                   1152: 
                   1153: /*----------------------------------------------------------------------------
                   1154:  | Log base e
                   1155:  *----------------------------------------------------------------------------*/
                   1156: 
1.1.1.2 ! root     1157: floatx80 floatx80_logn(floatx80 a, float_ctrl* c)
1.1       root     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) {
1.1.1.2 ! root     1173:         if ((bits64) (aSig<<1)) propagateFloatx80NaNOneArg(a, c);
1.1       root     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
1.1.1.2 ! root     1182:             float_raise(float_flag_divbyzero, c);
1.1       root     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) {
1.1.1.2 ! root     1198:         float_raise(float_flag_invalid, c);
1.1       root     1199:         a.low = floatx80_default_nan_low;
                   1200:         a.high = floatx80_default_nan_high;
                   1201:         return a;
                   1202:     }
                   1203:     
1.1.1.2 ! root     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);
1.1       root     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:         
1.1.1.2 ! root     1222:         fp0 = floatx80_sub(fp0, f, c); // Y-F
1.1       root     1223:         
                   1224:         // LP1CONT1
1.1.1.2 ! root     1225:         fp0 = floatx80_mul(fp0, log_tbl[j], c); // FP0 IS U = (Y-F)/F
1.1       root     1226:         logof2 = packFloatx80(0, 0x3FFE, LIT64(0xB17217F7D1CF79AC));
1.1.1.2 ! root     1227:         klog2 = floatx80_mul(fp1, logof2, c); // FP1 IS K*LOG2
        !          1228:         fp2 = floatx80_mul(fp0, fp0, c); // FP2 IS V=U*U
1.1       root     1229:         
                   1230:         fp3 = fp2;
                   1231:         fp1 = fp2;
                   1232:         
1.1.1.2 ! root     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)
1.1       root     1248:         
1.1.1.2 ! root     1249:         set_float_rounding_mode(user_rnd_mode, c);
        !          1250:         set_float_rounding_precision(user_rnd_prec, c);
1.1       root     1251:         
1.1.1.2 ! root     1252:         a = floatx80_add(fp0, klog2, c);
1.1       root     1253:         
1.1.1.2 ! root     1254:         float_raise(float_flag_inexact, c);
1.1       root     1255:         
                   1256:         return a;
                   1257:     } else { // |X-1| >= 1/16
                   1258:         fp0 = a;
                   1259:         fp1 = a;
1.1.1.2 ! root     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)
1.1       root     1263:         
                   1264:         // LP1CONT2
1.1.1.2 ! root     1265:         fp1 = floatx80_div(fp1, fp0, c); // U
1.1       root     1266:         saveu = fp1;
1.1.1.2 ! root     1267:         fp0 = floatx80_mul(fp1, fp1, c); // FP0 IS V = U*U
        !          1268:         fp1 = floatx80_mul(fp0, fp0, c); // FP1 IS W = V*V
1.1       root     1269:         
1.1.1.2 ! root     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)] )
1.1       root     1283:         
1.1.1.2 ! root     1284:         set_float_rounding_mode(user_rnd_mode, c);
        !          1285:         set_float_rounding_precision(user_rnd_prec, c);
1.1       root     1286:         
1.1.1.2 ! root     1287:         a = floatx80_add(fp0, saveu, c);
1.1       root     1288:         
                   1289:         //if (!floatx80_is_zero(a)) {
1.1.1.2 ! root     1290:             float_raise(float_flag_inexact, c);
1.1       root     1291:         //}
                   1292:         
                   1293:         return a;
                   1294:     }
                   1295: }
                   1296: 
                   1297: /*----------------------------------------------------------------------------
                   1298:  | Log base e of x plus 1
                   1299:  *----------------------------------------------------------------------------*/
                   1300: 
1.1.1.2 ! root     1301: floatx80 floatx80_lognp1(floatx80 a, float_ctrl* c)
1.1       root     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) {
1.1.1.2 ! root     1317:         if ((bits64) (aSig<<1)) propagateFloatx80NaNOneArg(a, c);
1.1       root     1318:         if (aSign) {
1.1.1.2 ! root     1319:             float_raise(float_flag_invalid, c);
1.1       root     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) {
1.1.1.2 ! root     1333:             float_raise(float_flag_divbyzero, c);
1.1       root     1334:             packFloatx80(aSign, 0x7FFF, floatx80_default_infinity_low);
                   1335:         }
1.1.1.2 ! root     1336:         float_raise(float_flag_invalid, c);
1.1       root     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
1.1.1.2 ! root     1343:         float_raise(float_flag_inexact, c);
        !          1344:         return floatx80_move(a, c);
1.1       root     1345:     }
                   1346:     
1.1.1.2 ! root     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);
1.1       root     1351:     
                   1352:     compact = floatx80_make_compact(aExp, aSig);
                   1353:     
                   1354:     fp0 = a; // Z
                   1355:     fp1 = a;
                   1356:     
1.1.1.2 ! root     1357:     fp0 = floatx80_add(fp0, float32_to_floatx80(0x3F800000, c), c); // X = (1+Z)
1.1       root     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:         
1.1.1.2 ! root     1374:         fp0 = floatx80_sub(fp0, f, c); // Y-F
1.1       root     1375:         
                   1376:     lp1cont1:
                   1377:         // LP1CONT1
1.1.1.2 ! root     1378:         fp0 = floatx80_mul(fp0, log_tbl[j], c); // FP0 IS U = (Y-F)/F
1.1       root     1379:         logof2 = packFloatx80(0, 0x3FFE, LIT64(0xB17217F7D1CF79AC));
1.1.1.2 ! root     1380:         klog2 = floatx80_mul(fp1, logof2, c); // FP1 IS K*LOG2
        !          1381:         fp2 = floatx80_mul(fp0, fp0, c); // FP2 IS V=U*U
1.1       root     1382:         
                   1383:         fp3 = fp2;
                   1384:         fp1 = fp2;
                   1385:         
1.1.1.2 ! root     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)
1.1       root     1401:         
1.1.1.2 ! root     1402:         set_float_rounding_mode(user_rnd_mode, c);
        !          1403:         set_float_rounding_precision(user_rnd_prec, c);
1.1       root     1404:         
1.1.1.2 ! root     1405:         a = floatx80_add(fp0, klog2, c);
1.1       root     1406:         
1.1.1.2 ! root     1407:         float_raise(float_flag_inexact, c);
1.1       root     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
1.1.1.2 ! root     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
1.1       root     1420:             fp1 = packFloatx80(0, 0, 0); // K = 0
                   1421:         } else {
                   1422:             // KISNEG
1.1.1.2 ! root     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
1.1       root     1426:             fp1 = packFloatx80(1, one_exp, one_sig); // K = -1
                   1427:         }
                   1428:         goto lp1cont1;
                   1429:     } else {
                   1430:         // LP1ONE16
1.1.1.2 ! root     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
1.1       root     1433:         
                   1434:         // LP1CONT2
1.1.1.2 ! root     1435:         fp1 = floatx80_div(fp1, fp0, c); // U
1.1       root     1436:         saveu = fp1;
1.1.1.2 ! root     1437:         fp0 = floatx80_mul(fp1, fp1, c); // FP0 IS V = U*U
        !          1438:         fp1 = floatx80_mul(fp0, fp0, c); // FP1 IS W = V*V
1.1       root     1439:         
1.1.1.2 ! root     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)] )
1.1       root     1453:         
1.1.1.2 ! root     1454:         set_float_rounding_mode(user_rnd_mode, c);
        !          1455:         set_float_rounding_precision(user_rnd_prec, c);
1.1       root     1456:         
1.1.1.2 ! root     1457:         a = floatx80_add(fp0, saveu, c);
1.1       root     1458:         
                   1459:         //if (!floatx80_is_zero(a)) {
1.1.1.2 ! root     1460:             float_raise(float_flag_inexact, c);
1.1       root     1461:         //}
                   1462:         
                   1463:         return a;
                   1464:     }
                   1465: }
                   1466: 
                   1467: /*----------------------------------------------------------------------------
                   1468:  | Sine
                   1469:  *----------------------------------------------------------------------------*/
                   1470: 
1.1.1.2 ! root     1471: floatx80 floatx80_sin(floatx80 a, float_ctrl* c)
1.1       root     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) {
1.1.1.2 ! root     1489:         if ((bits64) (aSig<<1)) return propagateFloatx80NaNOneArg(a, c);
        !          1490:         float_raise(float_flag_invalid, c);
1.1       root     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:     
1.1.1.2 ! root     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);
1.1       root     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));
1.1.1.2 ! root     1518:                 fp0 = floatx80_add(fp0, twopi1, c);
1.1       root     1519:                 fp1 = fp0;
1.1.1.2 ! root     1520:                 fp0 = floatx80_add(fp0, twopi2, c);
        !          1521:                 fp1 = floatx80_sub(fp1, fp0, c);
        !          1522:                 fp1 = floatx80_add(fp1, twopi2, c);
1.1       root     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:             
1.1.1.2 ! root     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
1.1       root     1551:             fp3 = fp0; // FP3 is A
1.1.1.2 ! root     1552:             fp1 = floatx80_sub(fp1, fp4, c); // FP1 is a := r - p
        !          1553:             fp0 = floatx80_add(fp0, fp1, c); // FP0 is R := A+a
1.1       root     1554:             
                   1555:             if (endflag > 0) {
1.1.1.2 ! root     1556:                 n = floatx80_to_int32(fp2, c);
1.1       root     1557:                 goto sincont;
                   1558:             }
1.1.1.2 ! root     1559:             fp3 = floatx80_sub(fp3, fp0, c); // A-R
        !          1560:             fp1 = floatx80_add(fp1, fp3, c); // FP1 is r := (A-R)+a
1.1       root     1561:             goto loop;
                   1562:         } else {
                   1563:             // SINSM
1.1.1.2 ! root     1564:             fp0 = float32_to_floatx80(0x3F800000, c); // 1
1.1       root     1565:             
1.1.1.2 ! root     1566:             set_float_rounding_mode(user_rnd_mode, c);
        !          1567:             set_float_rounding_precision(user_rnd_prec, c);
1.1       root     1568:             
                   1569:             if (adjn) {
                   1570:                 // COSTINY
1.1.1.2 ! root     1571:                 a = floatx80_sub(fp0, float32_to_floatx80(0x00800000, c), c);
1.1       root     1572:             } else {
                   1573:                 // SINTINY
1.1.1.2 ! root     1574:                 a = floatx80_move(a, c);
1.1       root     1575:             }
1.1.1.2 ! root     1576:             float_raise(float_flag_inexact, c);
1.1       root     1577:             
                   1578:             return a;
                   1579:         }
                   1580:     } else {
1.1.1.2 ! root     1581:         fp1 = floatx80_mul(fp0, float64_to_floatx80(LIT64(0x3FE45F306DC9C883), c), c); // X*2/PI
1.1       root     1582:         
1.1.1.2 ! root     1583:         n = floatx80_to_int32(fp1, c);
1.1       root     1584:         j = 32 + n;
                   1585:         
1.1.1.2 ! root     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
1.1       root     1588:         
                   1589:     sincont:
                   1590:         if ((n + adjn) & 1) {
                   1591:             // COSPOLY
1.1.1.2 ! root     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
1.1       root     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:             
1.1.1.2 ! root     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)
1.1       root     1616:             fp4 = packFloatx80(1, 0x3FF5, LIT64(0xB60B60B60B61D438));
1.1.1.2 ! root     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))
1.1       root     1620:             fp4 = packFloatx80(0, 0x3FFA, LIT64(0xAAAAAAAAAAAAAB5E));
1.1.1.2 ! root     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)))]
1.1       root     1625:             
                   1626:             x = packFloatx80(xSign, xExp, xSig);
1.1.1.2 ! root     1627:             fp0 = floatx80_mul(fp0, x, c);
1.1       root     1628:             
1.1.1.2 ! root     1629:             set_float_rounding_mode(user_rnd_mode, c);
        !          1630:             set_float_rounding_precision(user_rnd_prec, c);
1.1       root     1631:             
1.1.1.2 ! root     1632:             a = floatx80_add(fp0, float32_to_floatx80(posneg1, c), c);
1.1       root     1633:             
1.1.1.2 ! root     1634:             float_raise(float_flag_inexact, c);
1.1       root     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:             
1.1.1.2 ! root     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)
1.1       root     1656:             fp4 = packFloatx80(0, 0x3FF8, LIT64(0x88888888888859AF));
1.1.1.2 ! root     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))
1.1       root     1660:             fp4 = packFloatx80(1, 0x3FFC, LIT64(0xAAAAAAAAAAAAAA99));
1.1.1.2 ! root     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))]
1.1       root     1663:             
                   1664:             x = packFloatx80(xSign, xExp, xSig);
1.1.1.2 ! root     1665:             fp0 = floatx80_mul(fp0, x, c); // R'*S
        !          1666:             fp0 = floatx80_mul(fp0, fp1, c); // SIN(R')-R'
1.1       root     1667:             
1.1.1.2 ! root     1668:             set_float_rounding_mode(user_rnd_mode, c);
        !          1669:             set_float_rounding_precision(user_rnd_prec, c);
1.1       root     1670:             
1.1.1.2 ! root     1671:             a = floatx80_add(fp0, x, c);
1.1       root     1672:             
1.1.1.2 ! root     1673:             float_raise(float_flag_inexact, c);
1.1       root     1674:             
                   1675:             return a;
                   1676:         }
                   1677:     }
                   1678: }
                   1679: 
                   1680: /*----------------------------------------------------------------------------
                   1681:  | Hyperbolic sine
                   1682:  *----------------------------------------------------------------------------*/
                   1683: 
1.1.1.2 ! root     1684: floatx80 floatx80_sinh(floatx80 a, float_ctrl* c)
1.1       root     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) {
1.1.1.2 ! root     1701:         if ((bits64) (aSig<<1)) return propagateFloatx80NaNOneArg(a, c);
1.1       root     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:     
1.1.1.2 ! root     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);
1.1       root     1713:     
                   1714:     compact = floatx80_make_compact(aExp, aSig);
                   1715: 
                   1716:     if (compact > 0x400CB167) {
                   1717:         // SINHBIG
                   1718:         if (compact > 0x400CB2B3) {
1.1.1.2 ! root     1719:             set_float_rounding_mode(user_rnd_mode, c);
        !          1720:             set_float_rounding_precision(user_rnd_prec, c);
1.1       root     1721:             
1.1.1.2 ! root     1722:             return roundAndPackFloatx80(get_float_rounding_precision(c), aSign, 0x8000, aSig, 0, c);
1.1       root     1723:         } else {
1.1.1.2 ! root     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);
1.1       root     1728:             fp2 = packFloatx80(aSign, 0x7FFB, one_sig);
                   1729:             
1.1.1.2 ! root     1730:             set_float_rounding_mode(user_rnd_mode, c);
        !          1731:             set_float_rounding_precision(user_rnd_prec, c);
1.1       root     1732:             
1.1.1.2 ! root     1733:             a = floatx80_mul(fp0, fp2, c);
1.1       root     1734:             
1.1.1.2 ! root     1735:             float_raise(float_flag_inexact, c);
1.1       root     1736:             
                   1737:             return a;
                   1738:         }
                   1739:     } else { // |X| < 16380 LOG2
1.1.1.2 ! root     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
1.1       root     1743:         fp2 = fp0;
1.1.1.2 ! root     1744:         fp0 = floatx80_div(fp0, fp1, c); // Z/(1+Z)
        !          1745:         fp0 = floatx80_add(fp0, fp2, c);
1.1       root     1746:         
                   1747:         fact = 0x3F000000;
                   1748:         fact |= aSign ? 0x80000000 : 0x00000000;
                   1749:         
1.1.1.2 ! root     1750:         set_float_rounding_mode(user_rnd_mode, c);
        !          1751:         set_float_rounding_precision(user_rnd_prec, c);
1.1       root     1752:         
1.1.1.2 ! root     1753:         a = floatx80_mul(fp0, float32_to_floatx80(fact, c), c);
1.1       root     1754:         
1.1.1.2 ! root     1755:         float_raise(float_flag_inexact, c);
1.1       root     1756:         
                   1757:         return a;
                   1758:     }
                   1759: }
                   1760: 
                   1761: /*----------------------------------------------------------------------------
                   1762:  | Tangent
                   1763:  *----------------------------------------------------------------------------*/
                   1764: 
1.1.1.2 ! root     1765: floatx80 floatx80_tan(floatx80 a, float_ctrl* c)
1.1       root     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) {
1.1.1.2 ! root     1783:         if ((bits64) (aSig<<1)) return propagateFloatx80NaNOneArg(a, c);
        !          1784:         float_raise(float_flag_invalid, c);
1.1       root     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:     
1.1.1.2 ! root     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);
1.1       root     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));
1.1.1.2 ! root     1810:                 fp0 = floatx80_add(fp0, twopi1, c);
1.1       root     1811:                 fp1 = fp0;
1.1.1.2 ! root     1812:                 fp0 = floatx80_add(fp0, twopi2, c);
        !          1813:                 fp1 = floatx80_sub(fp1, fp0, c);
        !          1814:                 fp1 = floatx80_add(fp1, twopi2, c);
1.1       root     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:             
1.1.1.2 ! root     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
1.1       root     1843:             fp3 = fp0; // FP3 is A
1.1.1.2 ! root     1844:             fp1 = floatx80_sub(fp1, fp4, c); // FP1 is a := r - p
        !          1845:             fp0 = floatx80_add(fp0, fp1, c); // FP0 is R := A+a
1.1       root     1846:             
                   1847:             if (endflag > 0) {
1.1.1.2 ! root     1848:                 n = floatx80_to_int32(fp2, c);
1.1       root     1849:                 goto tancont;
                   1850:             }
1.1.1.2 ! root     1851:             fp3 = floatx80_sub(fp3, fp0, c); // A-R
        !          1852:             fp1 = floatx80_add(fp1, fp3, c); // FP1 is r := (A-R)+a
1.1       root     1853:             goto loop;
                   1854:         } else {
1.1.1.2 ! root     1855:             set_float_rounding_mode(user_rnd_mode, c);
        !          1856:             set_float_rounding_precision(user_rnd_prec, c);
1.1       root     1857:             
1.1.1.2 ! root     1858:             a = floatx80_move(a, c);
1.1       root     1859:             
1.1.1.2 ! root     1860:             float_raise(float_flag_inexact, c);
1.1       root     1861:             
                   1862:             return a;
                   1863:         }
                   1864:     } else {
1.1.1.2 ! root     1865:         fp1 = floatx80_mul(fp0, float64_to_floatx80(LIT64(0x3FE45F306DC9C883), c), c); // X*2/PI
1.1       root     1866:         
1.1.1.2 ! root     1867:         n = floatx80_to_int32(fp1, c);
1.1       root     1868:         j = 32 + n;
                   1869:         
1.1.1.2 ! root     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
1.1       root     1872:         
                   1873:     tancont:
                   1874:         if (n & 1) {
                   1875:             // NODD
                   1876:             fp1 = fp0; // R
1.1.1.2 ! root     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
1.1       root     1883:             fp4 = packFloatx80(0, 0x3FF6, LIT64(0xE073D3FC199C4A00));
1.1.1.2 ! root     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)
1.1       root     1887:             fp4 = packFloatx80(0, 0x3FF9, LIT64(0xD23CD68415D95FA1));
1.1.1.2 ! root     1888:             fp3 = floatx80_add(fp3, fp4, c); // Q2+S(Q3+SQ4)
1.1       root     1889:             fp4 = packFloatx80(1, 0x3FFC, LIT64(0x8895A6C5FB423BCA));
1.1.1.2 ! root     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))
1.1       root     1893:             fp4 = packFloatx80(1, 0x3FFD, LIT64(0xEEF57E0DA84BC8CE));
1.1.1.2 ! root     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)))
1.1       root     1899:             
                   1900:             xSign = extractFloatx80Sign(fp1);
                   1901:             xExp = extractFloatx80Exp(fp1);
                   1902:             xSig = extractFloatx80Frac(fp1);
                   1903:             xSign ^= 1;
                   1904:             fp1 = packFloatx80(xSign, xExp, xSig);
                   1905: 
1.1.1.2 ! root     1906:             set_float_rounding_mode(user_rnd_mode, c);
        !          1907:             set_float_rounding_precision(user_rnd_prec, c);
1.1       root     1908:             
1.1.1.2 ! root     1909:             a = floatx80_div(fp0, fp1, c);
1.1       root     1910:             
1.1.1.2 ! root     1911:             float_raise(float_flag_inexact, c);
1.1       root     1912:             
                   1913:             return a;
                   1914:         } else {
1.1.1.2 ! root     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
1.1       root     1921:             fp4 = packFloatx80(0, 0x3FF6, LIT64(0xE073D3FC199C4A00));
1.1.1.2 ! root     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)
1.1       root     1925:             fp4 = packFloatx80(0, 0x3FF9, LIT64(0xD23CD68415D95FA1));
1.1.1.2 ! root     1926:             fp3 = floatx80_add(fp3, fp4, c); // Q2+S(Q3+SQ4)
1.1       root     1927:             fp4 = packFloatx80(1, 0x3FFC, LIT64(0x8895A6C5FB423BCA));
1.1.1.2 ! root     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))
1.1       root     1931:             fp4 = packFloatx80(1, 0x3FFD, LIT64(0xEEF57E0DA84BC8CE));
1.1.1.2 ! root     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)))
1.1       root     1937:             
1.1.1.2 ! root     1938:             set_float_rounding_mode(user_rnd_mode, c);
        !          1939:             set_float_rounding_precision(user_rnd_prec, c);
1.1       root     1940:             
1.1.1.2 ! root     1941:             a = floatx80_div(fp0, fp1, c);
1.1       root     1942:             
1.1.1.2 ! root     1943:             float_raise(float_flag_inexact, c);
1.1       root     1944:             
                   1945:             return a;
                   1946:         }
                   1947:     }
                   1948: }
                   1949: 
                   1950: /*----------------------------------------------------------------------------
                   1951:  | Hyperbolic tangent
                   1952:  *----------------------------------------------------------------------------*/
                   1953: 
1.1.1.2 ! root     1954: floatx80 floatx80_tanh(floatx80 a, float_ctrl* c)
1.1       root     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) {
1.1.1.2 ! root     1971:         if ((bits64) (aSig<<1)) return propagateFloatx80NaNOneArg(a, c);
1.1       root     1972:         return packFloatx80(aSign, one_exp, one_sig);
                   1973:     }
                   1974:     
                   1975:     if (aExp == 0 && aSig == 0) {
                   1976:         return packFloatx80(aSign, 0, 0);
                   1977:     }
                   1978:     
1.1.1.2 ! root     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);
1.1       root     1983:     
                   1984:     compact = floatx80_make_compact(aExp, aSig);
                   1985:     
                   1986:     if (compact < 0x3FD78000 || compact > 0x3FFFDDCE) {
                   1987:         // TANHBORS
                   1988:         if (compact < 0x3FFF8000) {
                   1989:             // TANHSM
1.1.1.2 ! root     1990:             set_float_rounding_mode(user_rnd_mode, c);
        !          1991:             set_float_rounding_precision(user_rnd_prec, c);
1.1       root     1992:             
1.1.1.2 ! root     1993:             a = floatx80_move(a, c);
1.1       root     1994:             
1.1.1.2 ! root     1995:             float_raise(float_flag_inexact, c);
1.1       root     1996:             
                   1997:             return a;
                   1998:         } else {
                   1999:             if (compact > 0x40048AA1) {
                   2000:                 // TANHHUGE
                   2001:                 sign = 0x3F800000;
                   2002:                 sign |= aSign ? 0x80000000 : 0x00000000;
1.1.1.2 ! root     2003:                 fp0 = float32_to_floatx80(sign, c);
1.1       root     2004:                 sign &= 0x80000000;
                   2005:                 sign ^= 0x80800000; // -SIGN(X)*EPS
                   2006:                 
1.1.1.2 ! root     2007:                 set_float_rounding_mode(user_rnd_mode, c);
        !          2008:                 set_float_rounding_precision(user_rnd_prec, c);
1.1       root     2009:                 
1.1.1.2 ! root     2010:                 a = floatx80_add(fp0, float32_to_floatx80(sign, c), c);
1.1       root     2011:                 
1.1.1.2 ! root     2012:                 float_raise(float_flag_inexact, c);
1.1       root     2013:                 
                   2014:                 return a;
                   2015:             } else {
                   2016:                 fp0 = packFloatx80(0, aExp+1, aSig); // Y = 2|X|
1.1.1.2 ! root     2017:                 fp0 = floatx80_etox(fp0, c); // FP0 IS EXP(Y)
        !          2018:                 fp0 = floatx80_add(fp0, float32_to_floatx80(0x3F800000, c), c); // EXP(Y)+1
1.1       root     2019:                 sign = aSign ? 0x80000000 : 0x00000000;
1.1.1.2 ! root     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
1.1       root     2022:                 
1.1.1.2 ! root     2023:                 set_float_rounding_mode(user_rnd_mode, c);
        !          2024:                 set_float_rounding_precision(user_rnd_prec, c);
1.1       root     2025:                 
1.1.1.2 ! root     2026:                 a = floatx80_add(fp1, fp0, c);
1.1       root     2027:                 
1.1.1.2 ! root     2028:                 float_raise(float_flag_inexact, c);
1.1       root     2029:                 
                   2030:                 return a;
                   2031:             }
                   2032:         }
                   2033:     } else { // 2**(-40) < |X| < (5/2)LOG2
                   2034:         fp0 = packFloatx80(0, aExp+1, aSig); // Y = 2|X|
1.1.1.2 ! root     2035:         fp0 = floatx80_etoxm1(fp0, c); // FP0 IS Z = EXPM1(Y)
        !          2036:         fp1 = floatx80_add(fp0, float32_to_floatx80(0x40000000, c), c); // Z+2
1.1       root     2037:         
                   2038:         vSign = extractFloatx80Sign(fp1);
                   2039:         vExp = extractFloatx80Exp(fp1);
                   2040:         vSig = extractFloatx80Frac(fp1);
                   2041:         
                   2042:         fp1 = packFloatx80(vSign ^ aSign, vExp, vSig);
                   2043:         
1.1.1.2 ! root     2044:         set_float_rounding_mode(user_rnd_mode, c);
        !          2045:         set_float_rounding_precision(user_rnd_prec, c);
1.1       root     2046:         
1.1.1.2 ! root     2047:         a = floatx80_div(fp0, fp1, c);
1.1       root     2048:         
1.1.1.2 ! root     2049:         float_raise(float_flag_inexact, c);
1.1       root     2050:         
                   2051:         return a;
                   2052:     }
                   2053: }
                   2054: 
                   2055: /*----------------------------------------------------------------------------
                   2056:  | 10 to x
                   2057:  *----------------------------------------------------------------------------*/
                   2058: 
1.1.1.2 ! root     2059: floatx80 floatx80_tentox(floatx80 a, float_ctrl* c)
1.1       root     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) {
1.1.1.2 ! root     2075:         if ((bits64) (aSig<<1)) return propagateFloatx80NaNOneArg(a, c);
1.1       root     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:     
1.1.1.2 ! root     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);
1.1       root     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
1.1.1.2 ! root     2095:             set_float_rounding_mode(user_rnd_mode, c);
        !          2096:             set_float_rounding_precision(user_rnd_prec, c);
1.1       root     2097:             
                   2098:             if (aSign) {
1.1.1.2 ! root     2099:                 return roundAndPackFloatx80(get_float_rounding_precision(c), 0, -0x1000, aSig, 0, c);
1.1       root     2100:             } else {
1.1.1.2 ! root     2101:                 return roundAndPackFloatx80(get_float_rounding_precision(c), 0, 0x8000, aSig, 0, c);
1.1       root     2102:             }
                   2103:         } else { // |X| < 2^(-70)
1.1.1.2 ! root     2104:             set_float_rounding_mode(user_rnd_mode, c);
        !          2105:             set_float_rounding_precision(user_rnd_prec, c);
1.1       root     2106:             
1.1.1.2 ! root     2107:             a = floatx80_add(fp0, float32_to_floatx80(0x3F800000, c), c); // 1 + X
1.1       root     2108:             
1.1.1.2 ! root     2109:             float_raise(float_flag_inexact, c);
1.1       root     2110:             
                   2111:             return a;
                   2112:         }
                   2113:     } else { // 2^(-70) <= |X| <= 16480 LOG 2 / LOG 10
                   2114:         fp1 = fp0; // X
1.1.1.2 ! root     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)
1.1       root     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
1.1.1.2 ! root     2140:         fp1 = floatx80_mul(fp1, float64_to_floatx80(LIT64(0x3F734413509F8000), c), c); // N*(LOG2/64LOG10)_LEAD
1.1       root     2141:         fp3 = packFloatx80(1, 0x3FCD, LIT64(0xC0219DC1DA994FD2));
1.1.1.2 ! root     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
1.1       root     2145:         fp2 = packFloatx80(0, 0x4000, LIT64(0x935D8DDDAAA8AC17)); // LOG10
1.1.1.2 ! root     2146:         fp0 = floatx80_mul(fp0, fp2, c); // R
1.1       root     2147:         
                   2148:         // EXPR
1.1.1.2 ! root     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);
1.1       root     2168:         
1.1.1.2 ! root     2169:         set_float_rounding_mode(user_rnd_mode, c);
        !          2170:         set_float_rounding_precision(user_rnd_prec, c);
1.1       root     2171:         
1.1.1.2 ! root     2172:         a = floatx80_mul(fp0, adjfact, c);
1.1       root     2173:         
1.1.1.2 ! root     2174:         float_raise(float_flag_inexact, c);
1.1       root     2175:         
                   2176:         return a;
                   2177:     }
                   2178: }
                   2179: 
                   2180: /*----------------------------------------------------------------------------
                   2181:  | 2 to x
                   2182:  *----------------------------------------------------------------------------*/
                   2183: 
1.1.1.2 ! root     2184: floatx80 floatx80_twotox(floatx80 a, float_ctrl* c)
1.1       root     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) {
1.1.1.2 ! root     2200:         if ((bits64) (aSig<<1)) return propagateFloatx80NaNOneArg(a, c);
1.1       root     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:     
1.1.1.2 ! root     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);
1.1       root     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
1.1.1.2 ! root     2220:             set_float_rounding_mode(user_rnd_mode, c);
        !          2221:             set_float_rounding_precision(user_rnd_prec, c);
1.1       root     2222:             
                   2223:             if (aSign) {
1.1.1.2 ! root     2224:                 return roundAndPackFloatx80(get_float_rounding_precision(c), 0, -0x1000, aSig, 0, c);
1.1       root     2225:             } else {
1.1.1.2 ! root     2226:                 return roundAndPackFloatx80(get_float_rounding_precision(c), 0, 0x8000, aSig, 0, c);
1.1       root     2227:             }
                   2228:         } else { // |X| < 2^(-70)
1.1.1.2 ! root     2229:             set_float_rounding_mode(user_rnd_mode, c);
        !          2230:             set_float_rounding_precision(user_rnd_prec, c);
1.1       root     2231:             
1.1.1.2 ! root     2232:             a = floatx80_add(fp0, float32_to_floatx80(0x3F800000, c), c); // 1 + X
1.1       root     2233:             
1.1.1.2 ! root     2234:             float_raise(float_flag_inexact, c);
1.1       root     2235:             
                   2236:             return a;
                   2237:         }
                   2238:     } else { // 2^(-70) <= |X| <= 16480
                   2239:         fp1 = fp0; // X
1.1.1.2 ! root     2240:         fp1 = floatx80_mul(fp1, float32_to_floatx80(0x42800000, c), c); // X * 64
        !          2241:         n = floatx80_to_int32(fp1, c);
1.1       root     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:         
1.1.1.2 ! root     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)
1.1       root     2265:         fp2 = packFloatx80(0, 0x3FFE, LIT64(0xB17217F7D1CF79AC)); // LOG2
1.1.1.2 ! root     2266:         fp0 = floatx80_mul(fp0, fp2, c); // R
1.1       root     2267:         
                   2268:         // EXPR
1.1.1.2 ! root     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);
1.1       root     2288:         
1.1.1.2 ! root     2289:         set_float_rounding_mode(user_rnd_mode, c);
        !          2290:         set_float_rounding_precision(user_rnd_prec, c);
1.1       root     2291:         
1.1.1.2 ! root     2292:         a = floatx80_mul(fp0, adjfact, c);
1.1       root     2293:         
1.1.1.2 ! root     2294:         float_raise(float_flag_inexact, c);
1.1       root     2295:         
                   2296:         return a;
                   2297:     }
                   2298: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.