Annotation of coherent/b/kernel/emulator/poly_l2.c, revision 1.1

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: }

unix.superglobalmegacorp.com

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