Annotation of previous_trunk/src/softfloat/fsincos.c, revision 1.1.1.1

1.1       root        1: /*============================================================================
                      2: This source file is an extension to the SoftFloat IEC/IEEE Floating-point
                      3: Arithmetic Package, Release 2b, written for Bochs (x86 achitecture simulator)
                      4: floating point emulation.
                      5: 
                      6: THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE.  Although reasonable effort has
                      7: been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES
                      8: RESULT IN INCORRECT BEHAVIOR.  USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS
                      9: AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES,
                     10: COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE
                     11: EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE
                     12: INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR
                     13: OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE.
                     14: 
                     15: Derivative works are acceptable, even for commercial purposes, so long as
                     16: (1) the source code for the derivative work includes prominent notice that
                     17: the work is derivative, and (2) the source code includes prominent notice with
                     18: these four paragraphs for those parts of this code that are retained.
                     19: =============================================================================*/
                     20: 
                     21: /*============================================================================
                     22:  * Written for Bochs (x86 achitecture simulator) by
                     23:  *            Stanislav Shwartsman [sshwarts at sourceforge net]
                     24:  * ==========================================================================*/
                     25: 
                     26: #define FLOAT128
                     27: 
                     28: #define USE_estimateDiv128To64
                     29: #include "mamesf.h"
                     30: #include "softfloat.h"
                     31: #include "fpu_constant.h"
                     32: 
                     33: static const floatx80 floatx80_one = { 0x3fff, 0x8000000000000000U };
                     34: static const floatx80 floatx80_default_nan = { floatx80_default_nan_high, floatx80_default_nan_low };
                     35: 
                     36: #define packFloat2x128m(zHi, zLo) {(zHi), (zLo)}
                     37: #define PACK_FLOAT_128(hi,lo) packFloat2x128m(LIT64(hi),LIT64(lo))
                     38: 
                     39: #define EXP_BIAS 0x3FFF
                     40: 
                     41: 
                     42: /* reduce trigonometric function argument using 128-bit precision
                     43:    M_PI approximation */
                     44: static uint64_t argument_reduction_kernel(uint64_t aSig0, int Exp, uint64_t *zSig0, uint64_t *zSig1)
                     45: {
                     46:        uint64_t term0, term1, term2;
                     47:        uint64_t aSig1 = 0;
                     48: 
                     49:        shortShift128Left(aSig1, aSig0, Exp, &aSig1, &aSig0);
                     50:        uint64_t q = estimateDiv128To64(aSig1, aSig0, FLOAT_PI_HI);
                     51:        mul128By64To192(FLOAT_PI_HI, FLOAT_PI_LO, q, &term0, &term1, &term2);
                     52:        sub128(aSig1, aSig0, term0, term1, zSig1, zSig0);
                     53:        while ((int64_t)(*zSig1) < 0) {
                     54:                --q;
                     55:                add192(*zSig1, *zSig0, term2, 0, FLOAT_PI_HI, FLOAT_PI_LO, zSig1, zSig0, &term2);
                     56:        }
                     57:        *zSig1 = term2;
                     58:        return q;
                     59: }
                     60: 
                     61: static int reduce_trig_arg(int expDiff, int *zSign, uint64_t *aSig0, uint64_t *aSig1)
                     62: {
                     63:        uint64_t term0, term1, q = 0;
                     64: 
                     65:        if (expDiff < 0) {
                     66:                shift128Right(*aSig0, 0, 1, aSig0, aSig1);
                     67:                expDiff = 0;
                     68:        }
                     69:        if (expDiff > 0) {
                     70:                q = argument_reduction_kernel(*aSig0, expDiff, aSig0, aSig1);
                     71:        }
                     72:        else {
                     73:                if (FLOAT_PI_HI <= *aSig0) {
                     74:                        *aSig0 -= FLOAT_PI_HI;
                     75:                        q = 1;
                     76:                }
                     77:        }
                     78: 
                     79:        shift128Right(FLOAT_PI_HI, FLOAT_PI_LO, 1, &term0, &term1);
                     80:        if (! lt128(*aSig0, *aSig1, term0, term1))
                     81:        {
                     82:                int lt = lt128(term0, term1, *aSig0, *aSig1);
                     83:                int eq = eq128(*aSig0, *aSig1, term0, term1);
                     84: 
                     85:                if ((eq && (q & 1)) || lt) {
                     86:                        *zSign = !(*zSign);
                     87:                        ++q;
                     88:                }
                     89:                if (lt) sub128(FLOAT_PI_HI, FLOAT_PI_LO, *aSig0, *aSig1, aSig0, aSig1);
                     90:        }
                     91: 
                     92:        return (int)(q & 3);
                     93: }
                     94: 
                     95: #define SIN_ARR_SIZE 11
                     96: #define COS_ARR_SIZE 11
                     97: 
                     98: static float128 sin_arr[SIN_ARR_SIZE] =
                     99: {
                    100:        PACK_FLOAT_128(0x3fff000000000000, 0x0000000000000000), /*  1 */
                    101:        PACK_FLOAT_128(0xbffc555555555555, 0x5555555555555555), /*  3 */
                    102:        PACK_FLOAT_128(0x3ff8111111111111, 0x1111111111111111), /*  5 */
                    103:        PACK_FLOAT_128(0xbff2a01a01a01a01, 0xa01a01a01a01a01a), /*  7 */
                    104:        PACK_FLOAT_128(0x3fec71de3a556c73, 0x38faac1c88e50017), /*  9 */
                    105:        PACK_FLOAT_128(0xbfe5ae64567f544e, 0x38fe747e4b837dc7), /* 11 */
                    106:        PACK_FLOAT_128(0x3fde6124613a86d0, 0x97ca38331d23af68), /* 13 */
                    107:        PACK_FLOAT_128(0xbfd6ae7f3e733b81, 0xf11d8656b0ee8cb0), /* 15 */
                    108:        PACK_FLOAT_128(0x3fce952c77030ad4, 0xa6b2605197771b00), /* 17 */
                    109:        PACK_FLOAT_128(0xbfc62f49b4681415, 0x724ca1ec3b7b9675), /* 19 */
                    110:        PACK_FLOAT_128(0x3fbd71b8ef6dcf57, 0x18bef146fcee6e45)  /* 21 */
                    111: };
                    112: 
                    113: static float128 cos_arr[COS_ARR_SIZE] =
                    114: {
                    115:        PACK_FLOAT_128(0x3fff000000000000, 0x0000000000000000), /*  0 */
                    116:        PACK_FLOAT_128(0xbffe000000000000, 0x0000000000000000), /*  2 */
                    117:        PACK_FLOAT_128(0x3ffa555555555555, 0x5555555555555555), /*  4 */
                    118:        PACK_FLOAT_128(0xbff56c16c16c16c1, 0x6c16c16c16c16c17), /*  6 */
                    119:        PACK_FLOAT_128(0x3fefa01a01a01a01, 0xa01a01a01a01a01a), /*  8 */
                    120:        PACK_FLOAT_128(0xbfe927e4fb7789f5, 0xc72ef016d3ea6679), /* 10 */
                    121:        PACK_FLOAT_128(0x3fe21eed8eff8d89, 0x7b544da987acfe85), /* 12 */
                    122:        PACK_FLOAT_128(0xbfda93974a8c07c9, 0xd20badf145dfa3e5), /* 14 */
                    123:        PACK_FLOAT_128(0x3fd2ae7f3e733b81, 0xf11d8656b0ee8cb0), /* 16 */
                    124:        PACK_FLOAT_128(0xbfca6827863b97d9, 0x77bb004886a2c2ab), /* 18 */
                    125:        PACK_FLOAT_128(0x3fc1e542ba402022, 0x507a9cad2bf8f0bb)  /* 20 */
                    126: };
                    127: 
                    128: extern float128 OddPoly (float128 x, float128 *arr, unsigned n);
                    129: 
                    130: /* 0 <= x <= pi/4 */
                    131: INLINE float128 poly_sin(float128 x)
                    132: {
                    133:        //                 3     5     7     9     11     13     15
                    134:        //                x     x     x     x     x      x      x
                    135:        // sin (x) ~ x - --- + --- - --- + --- - ---- + ---- - ---- =
                    136:        //                3!    5!    7!    9!    11!    13!    15!
                    137:        //
                    138:        //                 2     4     6     8     10     12     14
                    139:        //                x     x     x     x     x      x      x
                    140:        //   = x * [ 1 - --- + --- - --- + --- - ---- + ---- - ---- ] =
                    141:        //                3!    5!    7!    9!    11!    13!    15!
                    142:        //
                    143:        //           3                          3
                    144:        //          --       4k                --        4k+2
                    145:        //   p(x) = >  C  * x   > 0     q(x) = >  C   * x     < 0
                    146:        //          --  2k                     --  2k+1
                    147:        //          k=0                        k=0
                    148:        //
                    149:        //                          2
                    150:        //   sin(x) ~ x * [ p(x) + x * q(x) ]
                    151:        //
                    152: 
                    153:        return OddPoly(x, sin_arr, SIN_ARR_SIZE);
                    154: }
                    155: 
                    156: extern float128 EvenPoly(float128 x, float128 *arr, unsigned n);
                    157: 
                    158: /* 0 <= x <= pi/4 */
                    159: INLINE float128 poly_cos(float128 x)
                    160: {
                    161:        //                 2     4     6     8     10     12     14
                    162:        //                x     x     x     x     x      x      x
                    163:        // cos (x) ~ 1 - --- + --- - --- + --- - ---- + ---- - ----
                    164:        //                2!    4!    6!    8!    10!    12!    14!
                    165:        //
                    166:        //           3                          3
                    167:        //          --       4k                --        4k+2
                    168:        //   p(x) = >  C  * x   > 0     q(x) = >  C   * x     < 0
                    169:        //          --  2k                     --  2k+1
                    170:        //          k=0                        k=0
                    171:        //
                    172:        //                      2
                    173:        //   cos(x) ~ [ p(x) + x * q(x) ]
                    174:        //
                    175: 
                    176:        return EvenPoly(x, cos_arr, COS_ARR_SIZE);
                    177: }
                    178: 
                    179: INLINE void sincos_invalid(floatx80 *sin_a, floatx80 *cos_a, floatx80 a)
                    180: {
                    181:        if (sin_a) *sin_a = a;
                    182:        if (cos_a) *cos_a = a;
                    183: }
                    184: 
                    185: INLINE void sincos_tiny_argument(floatx80 *sin_a, floatx80 *cos_a, floatx80 a)
                    186: {
                    187:        if (sin_a) *sin_a = a;
                    188:        if (cos_a) *cos_a = floatx80_one;
                    189: }
                    190: 
                    191: static floatx80 sincos_approximation(int neg, float128 r, uint64_t quotient)
                    192: {
                    193:        if (quotient & 0x1) {
                    194:                r = poly_cos(r);
                    195:                neg = 0;
                    196:        } else  {
                    197:                r = poly_sin(r);
                    198:        }
                    199: 
                    200:        floatx80 result = float128_to_floatx80(r);
                    201:        if (quotient & 0x2)
                    202:                neg = ! neg;
                    203: 
                    204:        if (neg)
                    205:                result = floatx80_chs(result);
                    206: 
                    207:        return result;
                    208: }
                    209: 
                    210: // =================================================
                    211: // SFFSINCOS               Compute sin(x) and cos(x)
                    212: // =================================================
                    213: 
                    214: //
                    215: // Uses the following identities:
                    216: // ----------------------------------------------------------
                    217: //
                    218: //  sin(-x) = -sin(x)
                    219: //  cos(-x) =  cos(x)
                    220: //
                    221: //  sin(x+y) = sin(x)*cos(y)+cos(x)*sin(y)
                    222: //  cos(x+y) = sin(x)*sin(y)+cos(x)*cos(y)
                    223: //
                    224: //  sin(x+ pi/2)  =  cos(x)
                    225: //  sin(x+ pi)    = -sin(x)
                    226: //  sin(x+3pi/2)  = -cos(x)
                    227: //  sin(x+2pi)    =  sin(x)
                    228: //
                    229: 
                    230: int sf_fsincos(floatx80 a, floatx80 *sin_a, floatx80 *cos_a)
                    231: {
                    232:        uint64_t aSig0, aSig1 = 0;
                    233:        int32_t aExp, zExp, expDiff;
                    234:        int aSign, zSign;
                    235:        int q = 0;
                    236: 
                    237:        aSig0 = extractFloatx80Frac(a);
                    238:        aExp = extractFloatx80Exp(a);
                    239:        aSign = extractFloatx80Sign(a);
                    240: 
                    241:        /* invalid argument */
                    242:        if (aExp == 0x7FFF) {
                    243:                if ((uint64_t) (aSig0<<1)) {
                    244:                        sincos_invalid(sin_a, cos_a, propagateFloatx80NaNOneArg(a));
                    245:                        return 0;
                    246:                }
                    247: 
                    248:                float_raise(float_flag_invalid);
                    249:                sincos_invalid(sin_a, cos_a, floatx80_default_nan);
                    250:                return 0;
                    251:        }
                    252: 
                    253:        if (aExp == 0) {
                    254:                if (aSig0 == 0) {
                    255:                        sincos_tiny_argument(sin_a, cos_a, a);
                    256:                        return 0;
                    257:                }
                    258: 
                    259: //        float_raise(float_flag_denormal);
                    260: 
                    261:                /* handle pseudo denormals */
                    262:                if (! (aSig0 & 0x8000000000000000U))
                    263:                {
                    264:                        float_raise(float_flag_inexact);
                    265:                        if (sin_a)
                    266:                                float_raise(float_flag_underflow);
                    267:                        sincos_tiny_argument(sin_a, cos_a, a);
                    268:                        return 0;
                    269:                }
                    270: 
                    271:                normalizeFloatx80Subnormal(aSig0, &aExp, &aSig0);
                    272:        }
                    273: 
                    274:        zSign = aSign;
                    275:        zExp = EXP_BIAS;
                    276:        expDiff = aExp - zExp;
                    277: 
                    278:        /* argument is out-of-range */
                    279:        if (expDiff >= 63)
                    280:                return -1;
                    281: 
                    282:        float_raise(float_flag_inexact);
                    283: 
                    284:        if (expDiff < -1) {    // doesn't require reduction
                    285:                if (expDiff <= -68) {
                    286:                        a = packFloatx80(aSign, aExp, aSig0);
                    287:                        sincos_tiny_argument(sin_a, cos_a, a);
                    288:                        return 0;
                    289:                }
                    290:                zExp = aExp;
                    291:        }
                    292:        else {
                    293:                q = reduce_trig_arg(expDiff, &zSign, &aSig0, &aSig1);
                    294:        }
                    295: 
                    296:        /* **************************** */
                    297:        /* argument reduction completed */
                    298:        /* **************************** */
                    299: 
                    300:        /* using float128 for approximation */
                    301:        float128 r = normalizeRoundAndPackFloat128(0, zExp-0x10, aSig0, aSig1);
                    302: 
                    303:        if (aSign) q = -q;
                    304:        if (cos_a) *cos_a = sincos_approximation(zSign, r, q+1);
                    305:        if (sin_a) *sin_a = sincos_approximation(zSign, r,   q);
                    306: 
                    307:        return 0;
                    308: }
                    309: 
                    310: int floatx80_fsincos(floatx80 a, floatx80 *sin_a, floatx80 *cos_a)
                    311: {
                    312:     return sf_fsincos(a, sin_a, cos_a);
                    313: }
                    314: 
                    315: int floatx80_fsin(floatx80 *a)
                    316: {
                    317:        return sf_fsincos(*a, a, 0);
                    318: }
                    319: 
                    320: int floatx80_fcos(floatx80 *a)
                    321: {
                    322:        return sf_fsincos(*a, 0, a);
                    323: }
                    324: 
                    325: // =================================================
                    326: // FPTAN                 Compute tan(x)
                    327: // =================================================
                    328: 
                    329: //
                    330: // Uses the following identities:
                    331: //
                    332: // 1. ----------------------------------------------------------
                    333: //
                    334: //  sin(-x) = -sin(x)
                    335: //  cos(-x) =  cos(x)
                    336: //
                    337: //  sin(x+y) = sin(x)*cos(y)+cos(x)*sin(y)
                    338: //  cos(x+y) = sin(x)*sin(y)+cos(x)*cos(y)
                    339: //
                    340: //  sin(x+ pi/2)  =  cos(x)
                    341: //  sin(x+ pi)    = -sin(x)
                    342: //  sin(x+3pi/2)  = -cos(x)
                    343: //  sin(x+2pi)    =  sin(x)
                    344: //
                    345: // 2. ----------------------------------------------------------
                    346: //
                    347: //           sin(x)
                    348: //  tan(x) = ------
                    349: //           cos(x)
                    350: //
                    351: 
                    352: int floatx80_ftan(floatx80 *a)
                    353: {
                    354:        uint64_t aSig0, aSig1 = 0;
                    355:        int32_t aExp, zExp, expDiff;
                    356:        int aSign, zSign;
                    357:        int q = 0;
                    358: 
                    359:        aSig0 = extractFloatx80Frac(*a);
                    360:        aExp = extractFloatx80Exp(*a);
                    361:        aSign = extractFloatx80Sign(*a);
                    362: 
                    363:        /* invalid argument */
                    364:        if (aExp == 0x7FFF) {
                    365:                if ((uint64_t) (aSig0<<1))
                    366:                {
                    367:                        *a = propagateFloatx80NaNOneArg(*a);
                    368:                        return 0;
                    369:                }
                    370: 
                    371:                float_raise(float_flag_invalid);
                    372:                *a = floatx80_default_nan;
                    373:                return 0;
                    374:        }
                    375: 
                    376:        if (aExp == 0) {
                    377:                if (aSig0 == 0) return 0;
                    378: //        float_raise(float_flag_denormal);
                    379:                /* handle pseudo denormals */
                    380:                if (! (aSig0 & 0x8000000000000000U))
                    381:                {
                    382:                        float_raise(float_flag_inexact | float_flag_underflow);
                    383:                        return 0;
                    384:                }
                    385:                normalizeFloatx80Subnormal(aSig0, &aExp, &aSig0);
                    386:        }
                    387: 
                    388:        zSign = aSign;
                    389:        zExp = EXP_BIAS;
                    390:        expDiff = aExp - zExp;
                    391: 
                    392:        /* argument is out-of-range */
                    393:        if (expDiff >= 63)
                    394:                return -1;
                    395: 
                    396:        float_raise(float_flag_inexact);
                    397: 
                    398:        if (expDiff < -1) {    // doesn't require reduction
                    399:                if (expDiff <= -68) {
                    400:                        *a = packFloatx80(aSign, aExp, aSig0);
                    401:                        return 0;
                    402:                }
                    403:                zExp = aExp;
                    404:        }
                    405:        else {
                    406:                q = reduce_trig_arg(expDiff, &zSign, &aSig0, &aSig1);
                    407:        }
                    408: 
                    409:        /* **************************** */
                    410:        /* argument reduction completed */
                    411:        /* **************************** */
                    412: 
                    413:        /* using float128 for approximation */
                    414:        float128 r = normalizeRoundAndPackFloat128(0, zExp-0x10, aSig0, aSig1);
                    415: 
                    416:        float128 sin_r = poly_sin(r);
                    417:        float128 cos_r = poly_cos(r);
                    418: 
                    419:        if (q & 0x1) {
                    420:                r = float128_div(cos_r, sin_r);
                    421:                zSign = ! zSign;
                    422:        } else {
                    423:                r = float128_div(sin_r, cos_r);
                    424:        }
                    425: 
                    426:        *a = float128_to_floatx80(r);
                    427:        if (zSign)
                    428:                *a = floatx80_chs(*a);
                    429: 
                    430:        return 0;
                    431: }
                    432: 
                    433: //                            2         3         4               n
                    434: // f(x) ~ C + (C * x) + (C * x) + (C * x) + (C * x) + ... + (C * x)
                    435: //         0    1         2         3         4               n
                    436: //
                    437: //          --       2k                --        2k+1
                    438: //   p(x) = >  C  * x           q(x) = >  C   * x
                    439: //          --  2k                     --  2k+1
                    440: //
                    441: //   f(x) ~ [ p(x) + x * q(x) ]
                    442: //
                    443: 
                    444: float128 EvalPoly(float128 x, float128 *arr, unsigned n)
                    445: {
                    446:        float128 x2 = float128_mul(x, x);
                    447:        unsigned i;
                    448: 
                    449:        assert(n > 1);
                    450: 
                    451:        float128 r1 = arr[--n];
                    452:        i = n;
                    453:        while(i >= 2) {
                    454:                r1 = float128_mul(r1, x2);
                    455:                i -= 2;
                    456:                r1 = float128_add(r1, arr[i]);
                    457:        }
                    458:        if (i) r1 = float128_mul(r1, x);
                    459: 
                    460:        float128 r2 = arr[--n];
                    461:        i = n;
                    462:        while(i >= 2) {
                    463:                r2 = float128_mul(r2, x2);
                    464:                i -= 2;
                    465:                r2 = float128_add(r2, arr[i]);
                    466:        }
                    467:        if (i) r2 = float128_mul(r2, x);
                    468: 
                    469:        return float128_add(r1, r2);
                    470: }
                    471: 
                    472: //                  2         4         6         8               2n
                    473: // f(x) ~ C + (C * x) + (C * x) + (C * x) + (C * x) + ... + (C * x)
                    474: //         0    1         2         3         4               n
                    475: //
                    476: //          --       4k                --        4k+2
                    477: //   p(x) = >  C  * x           q(x) = >  C   * x
                    478: //          --  2k                     --  2k+1
                    479: //
                    480: //                    2
                    481: //   f(x) ~ [ p(x) + x * q(x) ]
                    482: //
                    483: 
                    484: float128 EvenPoly(float128 x, float128 *arr, unsigned n)
                    485: {
                    486:                return EvalPoly(float128_mul(x, x), arr, n);
                    487: }
                    488: 
                    489: //                        3         5         7         9               2n+1
                    490: // f(x) ~ (C * x) + (C * x) + (C * x) + (C * x) + (C * x) + ... + (C * x)
                    491: //          0         1         2         3         4               n
                    492: //                        2         4         6         8               2n
                    493: //      = x * [ C + (C * x) + (C * x) + (C * x) + (C * x) + ... + (C * x)
                    494: //               0    1         2         3         4               n
                    495: //
                    496: //          --       4k                --        4k+2
                    497: //   p(x) = >  C  * x           q(x) = >  C   * x
                    498: //          --  2k                     --  2k+1
                    499: //
                    500: //                        2
                    501: //   f(x) ~ x * [ p(x) + x * q(x) ]
                    502: //
                    503: 
                    504: float128 OddPoly(float128 x, float128 *arr, unsigned n)
                    505: {
                    506:                return float128_mul(x, EvenPoly(x, arr, n));
                    507: }

unix.superglobalmegacorp.com

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