|
|
1.1 ! root 1: /*============================================================================ ! 2: ! 3: This C source file is an extension to the SoftFloat IEC/IEEE Floating-point ! 4: Arithmetic Package, Release 2a. ! 5: ! 6: =============================================================================*/ ! 7: ! 8: #include <stdint.h> ! 9: ! 10: #include "sysconfig.h" ! 11: #include "sysdeps.h" ! 12: ! 13: #define DECIMAL_LOG 0 ! 14: ! 15: #if DECIMAL_LOG ! 16: #define decimal_log write_log ! 17: #else ! 18: #define decimal_log(fmt, ...) ! 19: #endif ! 20: ! 21: #include "softfloat.h" ! 22: #include "softfloat-macros.h" ! 23: #include "softfloat/softfloat-specialize.h" ! 24: ! 25: /*---------------------------------------------------------------------------- ! 26: | Methods for converting decimal floats to binary extended precision floats. ! 27: *----------------------------------------------------------------------------*/ ! 28: ! 29: static void round128to64(flag aSign, int32_t *aExp, uint64_t *aSig0, uint64_t *aSig1, float_status *status) ! 30: { ! 31: flag increment; ! 32: int32_t zExp; ! 33: uint64_t zSig0, zSig1; ! 34: ! 35: zExp = *aExp; ! 36: zSig0 = *aSig0; ! 37: zSig1 = *aSig1; ! 38: ! 39: increment = ( (int64_t) zSig1 < 0 ); ! 40: if (status->float_rounding_mode != float_round_nearest_even) { ! 41: if (status->float_rounding_mode == float_round_to_zero) { ! 42: increment = 0; ! 43: } else { ! 44: if (aSign) { ! 45: increment = (status->float_rounding_mode == float_round_down) && zSig1; ! 46: } else { ! 47: increment = (status->float_rounding_mode == float_round_up) && zSig1; ! 48: } ! 49: } ! 50: } ! 51: ! 52: if (increment) { ! 53: ++zSig0; ! 54: if (zSig0 == 0) { ! 55: ++zExp; ! 56: zSig0 = LIT64(0x8000000000000000); ! 57: } else { ! 58: zSig0 &= ~ (((uint64_t) (zSig1<<1) == 0) & (status->float_rounding_mode == float_round_nearest_even)); ! 59: } ! 60: } else { ! 61: if ( zSig0 == 0 ) zExp = 0; ! 62: } ! 63: ! 64: *aExp = zExp; ! 65: *aSig0 = zSig0; ! 66: *aSig1 = 0; ! 67: } ! 68: ! 69: static void mul128by128round(int32_t *aExp, uint64_t *aSig0, uint64_t *aSig1, int32_t bExp, uint64_t bSig0, uint64_t bSig1, float_status *status) ! 70: { ! 71: int32_t zExp; ! 72: uint64_t zSig0, zSig1, zSig2, zSig3; ! 73: ! 74: zExp = *aExp; ! 75: zSig0 = *aSig0; ! 76: zSig1 = *aSig1; ! 77: ! 78: round128to64(0, &bExp, &bSig0, &bSig1, status); ! 79: ! 80: zExp += bExp - 0x3FFE; ! 81: mul128To256(zSig0, zSig1, bSig0, bSig1, &zSig0, &zSig1, &zSig2, &zSig3); ! 82: zSig1 |= (zSig2 | zSig3) != 0; ! 83: if ( 0 < (int64_t) zSig0 ) { ! 84: shortShift128Left( zSig0, zSig1, 1, &zSig0, &zSig1 ); ! 85: --zExp; ! 86: } ! 87: *aExp = zExp; ! 88: *aSig0 = zSig0; ! 89: *aSig1 = zSig1; ! 90: ! 91: round128to64(0, aExp, aSig0, aSig1, status); ! 92: } ! 93: ! 94: static void mul128by128(int32_t *aExp, uint64_t *aSig0, uint64_t *aSig1, int32_t bExp, uint64_t bSig0, uint64_t bSig1) ! 95: { ! 96: int32_t zExp; ! 97: uint64_t zSig0, zSig1, zSig2, zSig3; ! 98: ! 99: zExp = *aExp; ! 100: zSig0 = *aSig0; ! 101: zSig1 = *aSig1; ! 102: ! 103: zExp += bExp - 0x3FFE; ! 104: mul128To256(zSig0, zSig1, bSig0, bSig1, &zSig0, &zSig1, &zSig2, &zSig3); ! 105: zSig1 |= (zSig2 | zSig3) != 0; ! 106: if ( 0 < (int64_t) zSig0 ) { ! 107: shortShift128Left( zSig0, zSig1, 1, &zSig0, &zSig1 ); ! 108: --zExp; ! 109: } ! 110: *aExp = zExp; ! 111: *aSig0 = zSig0; ! 112: *aSig1 = zSig1; ! 113: } ! 114: ! 115: static void div128by128(int32_t *paExp, uint64_t *paSig0, uint64_t *paSig1, int32_t bExp, uint64_t bSig0, uint64_t bSig1) ! 116: { ! 117: int32_t zExp, aExp; ! 118: uint64_t zSig0, zSig1, aSig0, aSig1; ! 119: uint64_t rem0, rem1, rem2, rem3, term0, term1, term2, term3; ! 120: ! 121: aExp = *paExp; ! 122: aSig0 = *paSig0; ! 123: aSig1 = *paSig1; ! 124: ! 125: zExp = aExp - bExp + 0x3FFE; ! 126: if ( le128( bSig0, bSig1, aSig0, aSig1 ) ) { ! 127: shift128Right( aSig0, aSig1, 1, &aSig0, &aSig1 ); ! 128: ++zExp; ! 129: } ! 130: zSig0 = estimateDiv128To64( aSig0, aSig1, bSig0 ); ! 131: mul128By64To192( bSig0, bSig1, zSig0, &term0, &term1, &term2 ); ! 132: sub192( aSig0, aSig1, 0, term0, term1, term2, &rem0, &rem1, &rem2 ); ! 133: while ( (int64_t) rem0 < 0 ) { ! 134: --zSig0; ! 135: add192( rem0, rem1, rem2, 0, bSig0, bSig1, &rem0, &rem1, &rem2 ); ! 136: } ! 137: zSig1 = estimateDiv128To64( rem1, rem2, bSig0 ); ! 138: if ( ( zSig1 & 0x3FFF ) <= 4 ) { ! 139: mul128By64To192( bSig0, bSig1, zSig1, &term1, &term2, &term3 ); ! 140: sub192( rem1, rem2, 0, term1, term2, term3, &rem1, &rem2, &rem3 ); ! 141: while ( (int64_t) rem1 < 0 ) { ! 142: --zSig1; ! 143: add192( rem1, rem2, rem3, 0, bSig0, bSig1, &rem1, &rem2, &rem3 ); ! 144: } ! 145: zSig1 |= ( ( rem1 | rem2 | rem3 ) != 0 ); ! 146: } ! 147: ! 148: *paExp = zExp; ! 149: *paSig0 = zSig0; ! 150: *paSig1 = zSig1; ! 151: } ! 152: ! 153: #if 0 ! 154: ! 155: void tentoint128(flag mSign, flag eSign, int32_t *aExp, uint64_t *aSig0, uint64_t *aSig1, int32_t scale, float_status *status) ! 156: { ! 157: int32_t mExp; ! 158: uint64_t mSig0, mSig1; ! 159: ! 160: ! 161: *aExp = 0x3FFF; ! 162: *aSig0 = LIT64(0x8000000000000000); ! 163: *aSig1 = 0; ! 164: ! 165: mExp = 0x4002; ! 166: mSig0 = LIT64(0xA000000000000000); ! 167: mSig1 = 0; ! 168: ! 169: ! 170: while (scale) { ! 171: if (scale & 1) { ! 172: mul128by128round(aExp, aSig0, aSig1, mExp, mSig0, mSig1, status); ! 173: } ! 174: mul128by128(&mExp, &mSig0, &mSig1, mExp, mSig0, mSig1); ! 175: scale >>= 1; ! 176: } ! 177: } ! 178: ! 179: #else ! 180: ! 181: static void tentoint128(flag mSign, flag eSign, int32_t *aExp, uint64_t *aSig0, uint64_t *aSig1, int32_t scale, float_status *status) ! 182: { ! 183: int8_t save_rounding_mode; ! 184: int32_t mExp; ! 185: uint64_t mSig0, mSig1; ! 186: ! 187: save_rounding_mode = status->float_rounding_mode; ! 188: switch (status->float_rounding_mode) { ! 189: case float_round_nearest_even: ! 190: break; ! 191: case float_round_down: ! 192: if (mSign != eSign) { ! 193: set_float_rounding_mode(float_round_up, status); ! 194: } ! 195: break; ! 196: case float_round_up: ! 197: if (mSign != eSign) { ! 198: set_float_rounding_mode(float_round_down, status); ! 199: } ! 200: break; ! 201: case float_round_to_zero: ! 202: if (eSign == 0) { ! 203: set_float_rounding_mode(float_round_down, status); ! 204: } else { ! 205: set_float_rounding_mode(float_round_up, status); ! 206: } ! 207: break; ! 208: default: ! 209: break; ! 210: } ! 211: ! 212: *aExp = 0x3FFF; ! 213: *aSig0 = LIT64(0x8000000000000000); ! 214: *aSig1 = 0; ! 215: ! 216: mExp = 0x4002; ! 217: mSig0 = LIT64(0xA000000000000000); ! 218: mSig1 = 0; ! 219: ! 220: while (scale) { ! 221: if (scale & 1) { ! 222: mul128by128round(aExp, aSig0, aSig1, mExp, mSig0, mSig1, status); ! 223: } ! 224: mul128by128(&mExp, &mSig0, &mSig1, mExp, mSig0, mSig1); ! 225: scale >>= 1; ! 226: } ! 227: ! 228: set_float_rounding_mode(save_rounding_mode, status); ! 229: } ! 230: ! 231: #endif ! 232: ! 233: static int64_t tentointdec(int32_t scale) ! 234: { ! 235: uint64_t decM, decX; ! 236: ! 237: decX = 1; ! 238: decM = 10; ! 239: ! 240: while (scale) { ! 241: if (scale & 1) { ! 242: decX *= decM; ! 243: } ! 244: decM *= decM; ! 245: scale >>= 1; ! 246: } ! 247: ! 248: return decX; ! 249: } ! 250: ! 251: ! 252: static int64_t float128toint64(flag zSign, int32_t zExp, uint64_t zSig0, uint64_t zSig1, float_status *status) ! 253: { ! 254: int8_t roundingMode; ! 255: flag roundNearestEven, increment; ! 256: int64_t z; ! 257: ! 258: shift128RightJamming(zSig0, zSig1, 0x403E - zExp, &zSig0, &zSig1); ! 259: ! 260: roundingMode = status->float_rounding_mode; ! 261: roundNearestEven = (roundingMode == float_round_nearest_even); ! 262: increment = ((int64_t)zSig1 < 0); ! 263: if (!roundNearestEven) { ! 264: if (roundingMode == float_round_to_zero) { ! 265: increment = 0; ! 266: } else { ! 267: if (zSign) { ! 268: increment = (roundingMode == float_round_down ) && zSig1; ! 269: } else { ! 270: increment = (roundingMode == float_round_up ) && zSig1; ! 271: } ! 272: } ! 273: } ! 274: if (increment) { ! 275: ++zSig0; ! 276: zSig0 &= ~ (((uint64_t)(zSig1<<1) == 0) & roundNearestEven); ! 277: } ! 278: z = zSig0; ! 279: if (zSig1) float_raise(float_flag_inexact, status); ! 280: return z; ! 281: } ! 282: ! 283: static int32_t getDecimalExponent(int32_t aExp, uint64_t aSig) ! 284: { ! 285: flag zSign; ! 286: int32_t zExp, shiftCount; ! 287: uint64_t zSig0, zSig1; ! 288: ! 289: if (aSig == 0 || aExp == 0x3FFF) { ! 290: return 0; ! 291: } ! 292: if (aExp < 0) { ! 293: return -4932; ! 294: } ! 295: ! 296: aSig ^= LIT64(0x8000000000000000); ! 297: aExp -= 0x3FFF; ! 298: zSign = (aExp < 0); ! 299: aExp = zSign ? -aExp : aExp; ! 300: shiftCount = 31 - countLeadingZeros32(aExp); ! 301: zExp = 0x3FFF + shiftCount; ! 302: ! 303: if (shiftCount < 0) { ! 304: shortShift128Left(aSig, 0, -shiftCount, &zSig0, &zSig1); ! 305: } else { ! 306: shift128Right(aSig, 0, shiftCount, &zSig0, &zSig1); ! 307: aSig = (uint64_t)aExp << (63 - shiftCount); ! 308: if (zSign) { ! 309: sub128(aSig, 0, zSig0, zSig1, &zSig0, &zSig1); ! 310: } else { ! 311: add128(aSig, 0, zSig0, zSig1, &zSig0, &zSig1); ! 312: } ! 313: } ! 314: ! 315: shiftCount = countLeadingZeros64(zSig0); ! 316: shortShift128Left(zSig0, zSig1, shiftCount, &zSig0, &zSig1); ! 317: zExp -= shiftCount; ! 318: mul128by128(&zExp, &zSig0, &zSig1, 0x3FFD, LIT64(0x9A209A84FBCFF798), LIT64(0x8F8959AC0B7C9178)); ! 319: ! 320: shiftCount = 0x403E - zExp; ! 321: shift128RightJamming(zSig0, zSig1, shiftCount, &zSig0, &zSig1); ! 322: ! 323: if ((int64_t)zSig1 < 0) { ! 324: ++zSig0; ! 325: zSig0 &= ~(((int64_t)(zSig1<<1) == 0) & 1); ! 326: } ! 327: ! 328: zExp = zSign ? -zSig0 : zSig0; ! 329: ! 330: return zExp; ! 331: } ! 332: ! 333: /*---------------------------------------------------------------------------- ! 334: | Decimal to binary ! 335: *----------------------------------------------------------------------------*/ ! 336: ! 337: floatx80 floatdecimal_to_floatx80(floatx80 a, float_status *status) ! 338: { ! 339: flag decSign, zSign, decExpSign; ! 340: int32_t decExp, zExp, xExp, shiftCount; ! 341: uint64_t decSig, zSig0, zSig1, xSig0, xSig1; ! 342: ! 343: decSign = extractFloatx80Sign(a); ! 344: decExp = extractFloatx80Exp(a); ! 345: decSig = extractFloatx80Frac(a); ! 346: ! 347: if (decExp == 0x7FFF) return a; ! 348: ! 349: if (decExp == 0 && decSig == 0) return a; ! 350: ! 351: decExpSign = (decExp >> 14) & 1; ! 352: decExp &= 0x3FFF; ! 353: ! 354: shiftCount = countLeadingZeros64( decSig ); ! 355: zExp = 0x403E - shiftCount; ! 356: zSig0 = decSig << shiftCount; ! 357: zSig1 = 0; ! 358: zSign = decSign; ! 359: ! 360: tentoint128(decSign, decExpSign, &xExp, &xSig0, &xSig1, decExp, status); ! 361: ! 362: if (decExpSign) { ! 363: div128by128(&zExp, &zSig0, &zSig1, xExp, xSig0, xSig1); ! 364: } else { ! 365: mul128by128(&zExp, &zSig0, &zSig1, xExp, xSig0, xSig1); ! 366: } ! 367: ! 368: if (zSig1) float_raise(float_flag_decimal, status); ! 369: round128to64(zSign, &zExp, &zSig0, &zSig1, status); ! 370: ! 371: return packFloatx80( zSign, zExp, zSig0 ); ! 372: ! 373: } ! 374: ! 375: /*---------------------------------------------------------------------------- ! 376: | Binary to decimal ! 377: *----------------------------------------------------------------------------*/ ! 378: ! 379: floatx80 floatx80_to_floatdecimal(floatx80 a, int32_t *k, float_status *status) ! 380: { ! 381: flag aSign, decSign; ! 382: int32_t aExp, decExp, zExp, xExp; ! 383: uint64_t aSig, decSig, decX, zSig0, zSig1, xSig0, xSig1; ! 384: flag ictr, lambda; ! 385: int32_t kfactor, ilog, iscale, len; ! 386: ! 387: aSign = extractFloatx80Sign(a); ! 388: aExp = extractFloatx80Exp(a); ! 389: aSig = extractFloatx80Frac(a); ! 390: ! 391: if (aExp == 0x7FFF) { ! 392: if ((uint64_t) (aSig<<1)) return propagateFloatx80NaNOneArg(a, status); ! 393: return a; ! 394: } ! 395: ! 396: if (aExp == 0) { ! 397: if (aSig == 0) return packFloatx80(aSign, 0, 0); ! 398: normalizeFloatx80Subnormal(aSig, &aExp, &aSig); ! 399: } ! 400: ! 401: kfactor = *k; ! 402: ! 403: ilog = getDecimalExponent(aExp, aSig); ! 404: ! 405: ictr = 0; ! 406: ! 407: try_again: ! 408: decimal_log(_T("ILOG = %i\n"), ilog); ! 409: ! 410: if (kfactor > 0) { ! 411: if (kfactor > 17) { ! 412: kfactor = 17; ! 413: float_raise(float_flag_invalid, status); ! 414: } ! 415: len = kfactor; ! 416: } else { ! 417: len = ilog + 1 - kfactor; ! 418: if (len > 17) { ! 419: len = 17; ! 420: } ! 421: if (len < 1) { ! 422: len = 1; ! 423: } ! 424: if (kfactor > ilog) { ! 425: ilog = kfactor; ! 426: decimal_log(_T("ILOG is kfactor = %i\n"), ilog); ! 427: } ! 428: } ! 429: ! 430: decimal_log(_T("LEN = %i\n"),len); ! 431: ! 432: lambda = 0; ! 433: iscale = ilog + 1 - len; ! 434: ! 435: if (iscale < 0) { ! 436: lambda = 1; ! 437: iscale = -iscale; ! 438: } ! 439: ! 440: decimal_log(_T("ISCALE = %i, LAMBDA = %i\n"),iscale, lambda); ! 441: ! 442: tentoint128(lambda, 0, &xExp, &xSig0, &xSig1, iscale, status); ! 443: ! 444: decimal_log(_T("AFTER tentoint128: zExp = %04x, zSig0 = %16llx, zSig1 = %16llx\n"), xExp, xSig0, xSig1); ! 445: ! 446: zExp = aExp; ! 447: zSig0 = aSig; ! 448: zSig1 = 0; ! 449: ! 450: if (lambda) { ! 451: mul128by128(&zExp, &zSig0, &zSig1, xExp, xSig0, xSig1); ! 452: } else { ! 453: div128by128(&zExp, &zSig0, &zSig1, xExp, xSig0, xSig1); ! 454: } ! 455: ! 456: decimal_log(_T("BEFORE: zExp = %04x, zSig0 = %16llx, zSig1 = %16llx\n"),zExp,zSig0,zSig1); ! 457: ! 458: decSig = float128toint64(aSign, zExp, zSig0, zSig1, status); ! 459: ! 460: decimal_log(_T("AFTER: decSig = %llu\n"),decSig); ! 461: ! 462: if (ictr == 0) { ! 463: ! 464: decX = tentointdec(len - 1); ! 465: ! 466: if (decSig < decX) { // z < x ! 467: ilog -= 1; ! 468: ictr = 1; ! 469: goto try_again; ! 470: } ! 471: ! 472: decX *= 10; ! 473: ! 474: if (decSig > decX) { // z > x ! 475: ilog += 1; ! 476: ictr = 1; ! 477: goto try_again; ! 478: } ! 479: } ! 480: ! 481: decSign = aSign; ! 482: decExp = (ilog < 0) ? -ilog : ilog; ! 483: if (decExp > 999) { ! 484: float_raise(float_flag_invalid, status); ! 485: } ! 486: if (ilog < 0) decExp |= 0x4000; ! 487: ! 488: *k = len; ! 489: ! 490: return packFloatx80(decSign, decExp, decSig); ! 491: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.