|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.