|
|
1.1 ! root 1: /*---------------------------------------------------------------------------+ ! 2: | poly_l2.c | ! 3: | | ! 4: | Compute the base 2 log of a FPU_REG, using a polynomial approximation. | ! 5: | | ! 6: | Copyright (C) 1992 W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | ! 7: | Australia. E-mail [email protected] | ! 8: | | ! 9: | | ! 10: +---------------------------------------------------------------------------*/ ! 11: ! 12: #include "fpu_system.h" ! 13: #include "exception.h" ! 14: #include "reg_constant.h" ! 15: #include "fpu_emu.h" ! 16: ! 17: ! 18: ! 19: #define HIPOWER 9 ! 20: static unsigned short lterms[HIPOWER][4] = ! 21: { ! 22: /* Ideal computation with these coeffs gives about ! 23: 64.6 bit rel accuracy. */ ! 24: { 0xe177, 0xb82f, 0x7652, 0x7154 }, ! 25: { 0xee0f, 0xe80f, 0x2770, 0x7b1c }, ! 26: { 0x0fc0, 0xbe87, 0xb143, 0x49dd }, ! 27: { 0x78b9, 0xdadd, 0xec54, 0x34c2 }, ! 28: { 0x003a, 0x5de9, 0x628b, 0x2909 }, ! 29: { 0x5588, 0xed16, 0x4abf, 0x2193 }, ! 30: { 0xb461, 0x85f7, 0x347a, 0x1c6a }, ! 31: { 0x0975, 0x87b3, 0xd5bf, 0x1876 }, ! 32: { 0xe85c, 0xcec9, 0x84e7, 0x187d } ! 33: }; ! 34: ! 35: ! 36: ! 37: ! 38: /*--- poly_l2() -------------------------------------------------------------+ ! 39: | Base 2 logarithm by a polynomial approximation. | ! 40: +---------------------------------------------------------------------------*/ ! 41: void poly_l2(FPU_REG *arg, FPU_REG *result) ! 42: { ! 43: short exponent; ! 44: char zero; /* flag for an Xx == 0 */ ! 45: unsigned short bits, shift; ! 46: long long Xsq; ! 47: FPU_REG accum, denom, num, Xx; ! 48: ! 49: ! 50: exponent = arg->exp - EXP_BIAS; ! 51: ! 52: accum.tag = TW_Valid; /* set the tags to Valid */ ! 53: ! 54: if ( arg->sigh > (unsigned)0xb504f334 ) ! 55: { ! 56: /* This is good enough for the computation of the polynomial ! 57: sum, but actually results in a loss of precision for ! 58: the computation of Xx. This will matter only if exponent ! 59: becomes zero. */ ! 60: exponent++; ! 61: accum.sign = 1; /* sign to negative */ ! 62: num.exp = EXP_BIAS; /* needed to prevent errors in div routine */ ! 63: reg_u_div((long long *)&(CONST_1.sigl), (long long *)&(arg->sigl), &num); ! 64: } ! 65: else ! 66: { ! 67: accum.sign = 0; /* set the sign to positive */ ! 68: num.sigl = arg->sigl; /* copy the mantissa */ ! 69: num.sigh = arg->sigh; ! 70: } ! 71: ! 72: /* shift num left, lose the ms bit */ ! 73: num.sigh <<= 1; ! 74: if ( num.sigl & 0x80000000 ) num.sigh |= 1; ! 75: num.sigl <<= 1; ! 76: ! 77: denom.sigl = num.sigl; ! 78: denom.sigh = num.sigh; ! 79: poly_div4((long long *)&(denom.sigl)); ! 80: denom.sigh += 0x80000000; /* set the msb */ ! 81: Xx.exp = EXP_BIAS; /* needed to prevent errors in div routine */ ! 82: reg_u_div((long long *)&num.sigl, (long long *)&(denom.sigl), &Xx); ! 83: ! 84: zero = !(Xx.sigh | Xx.sigl); ! 85: ! 86: mul64((long long *)&Xx.sigl, (long long *)&Xx.sigl, &Xsq); ! 87: poly_div16(&Xsq); ! 88: ! 89: accum.exp = -1; /* exponent of accum */ ! 90: ! 91: /* Do the basic fixed point polynomial evaluation */ ! 92: polynomial((unsigned *)&accum.sigl, (unsigned *)&Xsq, lterms, HIPOWER-1); ! 93: ! 94: if ( !exponent ) ! 95: { ! 96: /* If the exponent is zero, then we would lose precision by ! 97: sticking to fixed point computation here */ ! 98: /* We need to re-compute Xx because of loss of precision. */ ! 99: FPU_REG lXx; ! 100: char sign; ! 101: ! 102: sign = accum.sign; ! 103: accum.sign = 0; ! 104: ! 105: /* make accum compatible and normalize */ ! 106: accum.exp = EXP_BIAS + accum.exp; ! 107: normalize(&accum); ! 108: ! 109: if ( zero ) ! 110: { ! 111: reg_move(&CONST_Z, result); ! 112: } ! 113: else ! 114: { ! 115: /* we need to re-compute lXx to better accuracy */ ! 116: num.tag = TW_Valid; /* set the tags to Vaild */ ! 117: num.sign = 0; /* set the sign to positive */ ! 118: num.exp = EXP_BIAS - 1; ! 119: if ( sign ) ! 120: { ! 121: /* The argument is of the form 1-x */ ! 122: /* Use 1-1/(1-x) = x/(1-x) */ ! 123: *((long long *)&num.sigl) = - *((long long *)&(arg->sigl)); ! 124: normalize(&num); ! 125: reg_div(&num, arg, &num); ! 126: } ! 127: else ! 128: { ! 129: normalize(&num); ! 130: } ! 131: ! 132: denom.tag = TW_Valid; /* set the tags to Valid */ ! 133: denom.sign = SIGN_POS; /* set the sign to positive */ ! 134: denom.exp = EXP_BIAS; ! 135: ! 136: reg_div(&num, &denom, &lXx); ! 137: ! 138: reg_u_mul(&lXx, &accum, &accum); ! 139: accum.exp += - EXP_BIAS + 1; ! 140: ! 141: reg_u_add(&lXx, &accum, result); ! 142: ! 143: normalize(result); ! 144: } ! 145: result->sign = sign; ! 146: return; ! 147: } ! 148: ! 149: mul64((long long *)&accum.sigl, ! 150: (long long *)&Xx.sigl, (long long *)&accum.sigl); ! 151: ! 152: *((long long *)(&accum.sigl)) += *((long long *)(&Xx.sigl)); ! 153: ! 154: if ( Xx.sigh > accum.sigh ) ! 155: { ! 156: /* There was an overflow */ ! 157: ! 158: poly_div2((long long *)&accum.sigl); ! 159: accum.sigh |= 0x80000000; ! 160: accum.exp++; ! 161: } ! 162: ! 163: /* When we add the exponent to the accum result later, we will ! 164: require that their signs are the same. Here we ensure that ! 165: this is so. */ ! 166: if ( exponent && ((exponent < 0) ^ (accum.sign)) ) ! 167: { ! 168: /* signs are different */ ! 169: ! 170: accum.sign = !accum.sign; ! 171: ! 172: /* An exceptional case is when accum is zero */ ! 173: if ( accum.sigl | accum.sigh ) ! 174: { ! 175: /* find 1-accum */ ! 176: /* Shift to get exponent == 0 */ ! 177: if ( accum.exp < 0 ) ! 178: { ! 179: poly_div2((long long *)&accum.sigl); ! 180: accum.exp++; ! 181: } ! 182: /* Just negate, but throw away the sign */ ! 183: *((long long *)&(accum.sigl)) = - *((long long *)&(accum.sigl)); ! 184: if ( exponent < 0 ) ! 185: exponent++; ! 186: else ! 187: exponent--; ! 188: } ! 189: } ! 190: ! 191: shift = exponent >= 0 ? exponent : -exponent ; ! 192: bits = 0; ! 193: if ( shift ) ! 194: { ! 195: if ( accum.exp ) ! 196: { ! 197: accum.exp++; ! 198: poly_div2((long long *)&accum.sigl); ! 199: } ! 200: while ( shift ) ! 201: { ! 202: poly_div2((long long *)&accum.sigl); ! 203: if ( shift & 1) ! 204: accum.sigh |= 0x80000000; ! 205: shift >>= 1; ! 206: bits++; ! 207: } ! 208: } ! 209: ! 210: /* Convert to 64 bit signed-compatible */ ! 211: accum.exp += bits + EXP_BIAS - 1; ! 212: ! 213: reg_move(&accum, result); ! 214: normalize(result); ! 215: ! 216: return; ! 217: } ! 218: ! 219: ! 220: /*--- poly_l2p1() -----------------------------------------------------------+ ! 221: | Base 2 logarithm by a polynomial approximation. | ! 222: | log2(x+1) | ! 223: +---------------------------------------------------------------------------*/ ! 224: int poly_l2p1(FPU_REG *arg, FPU_REG *result) ! 225: { ! 226: char sign = 0; ! 227: long long Xsq; ! 228: FPU_REG arg_pl1, denom, accum, local_arg, poly_arg; ! 229: ! 230: ! 231: sign = arg->sign; ! 232: ! 233: reg_add(arg, &CONST_1, &arg_pl1); ! 234: ! 235: if ( (arg_pl1.sign) | (arg_pl1.tag) ) ! 236: { /* We need a valid positive number! */ ! 237: return 1; ! 238: } ! 239: ! 240: reg_add(&CONST_1, &arg_pl1, &denom); ! 241: reg_div(arg, &denom, &local_arg); ! 242: local_arg.sign = 0; /* Make the sign positive */ ! 243: ! 244: /* Now we need to check that |local_arg| is less than ! 245: 3-2*sqrt(2) = 0.17157.. = .0xafb0ccc0 * 2^-2 */ ! 246: ! 247: if ( local_arg.exp >= EXP_BIAS - 3 ) ! 248: { ! 249: if ( (local_arg.exp > EXP_BIAS - 3) || ! 250: (local_arg.sigh > (unsigned)0xafb0ccc0) ) ! 251: { ! 252: /* The argument is large */ ! 253: poly_l2(&arg_pl1, result); return 0; ! 254: } ! 255: } ! 256: ! 257: /* Make a copy of local_arg */ ! 258: reg_move(&local_arg, &poly_arg); ! 259: ! 260: /* Get poly_arg bits aligned as required */ ! 261: shrx((unsigned *)&(poly_arg.sigl), -(poly_arg.exp - EXP_BIAS + 3)); ! 262: ! 263: mul64((long long *)&(poly_arg.sigl), (long long *)&(poly_arg.sigl), &Xsq); ! 264: poly_div16(&Xsq); ! 265: ! 266: /* Do the basic fixed point polynomial evaluation */ ! 267: polynomial(&(accum.sigl), (unsigned *)&Xsq, lterms, HIPOWER-1); ! 268: ! 269: accum.tag = TW_Valid; /* set the tags to Valid */ ! 270: accum.sign = SIGN_POS; /* and make accum positive */ ! 271: ! 272: /* make accum compatible and normalize */ ! 273: accum.exp = EXP_BIAS - 1; ! 274: normalize(&accum); ! 275: ! 276: reg_u_mul(&local_arg, &accum, &accum); ! 277: accum.exp -= EXP_BIAS - 1; ! 278: ! 279: reg_u_add(&local_arg, &accum, result); ! 280: ! 281: /* Multiply the result by 2 */ ! 282: result->exp++; ! 283: ! 284: result->sign = sign; ! 285: ! 286: return 0; ! 287: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.