Annotation of coherent/d/usr/lib/libmp/mdiv.c, revision 1.1.1.1

1.1       root        1: #include "mprec.h"
                      2: #include <assert.h>
                      3: #include <sys/mdata.h>
                      4: 
                      5: 
                      6: /*
                      7:  *     Mdiv sets the mints pointed to by "q" and "r" to the quotient
                      8:  *     and remainder (respectively) of dividing "a" by "b".  If "b"
                      9:  *     is zero, then it calls mperr with the appropriate message.
                     10:  *     The division is performed such that the following two properties
                     11:  *     hold :
                     12:  *             1. "r" + "q" * "b" = "a".
                     13:  *             2. The sign of "r" = the sign of "q".
                     14:  *             3. The abs. value of "r" < abs. value of "b".
                     15:  *     Note that no assumption is made as to the distinctness of "a",
                     16:  *     "b", "q" and "r".
                     17:  */
                     18: 
                     19: void
                     20: mdiv(a, b, q, r)
                     21: register mint *a, *b, *q, *r;
                     22: {
                     23:        int     apos, bpos;
                     24:        mint    al, bl;
                     25:        int     ispos();
                     26:        void    shortd(), longd();
                     27: 
                     28:        /* take care of small denominators */
                     29:        if (b->len <= 2 && (
                     30:                   b->len == 1                          /* 0 to BASE - 2 */
                     31:                || b->val[1] == NEFL                    /* -BASE to -2 */
                     32:                || b->val[1] == 0                       /* BASE - 1 */
                     33:                || (b->val[1] == 1 && b->val[0] == 0)   /* BASE */
                     34:                )
                     35:        ) {
                     36:                shortd(a, b, q, r);
                     37:                return;
                     38:        }
                     39: 
                     40:        /* make denominator negative */
                     41:        if (bpos = ispos(b)) {
                     42:                minit(&bl);
                     43:                mneg(b, &bl);
                     44:                b = &bl;
                     45:        }
                     46:        assert(b->len > 2);
                     47: 
                     48:        /* copy numerator, makeing it positive */
                     49:        minit(&al);
                     50:        if (apos = ispos(a))
                     51:                mcopy(a, &al);
                     52:        else
                     53:                mneg(a, &al);
                     54:        a = &al;
                     55: 
                     56:        /*
                     57:         *      BASE ^ (a->len - 1) <= a < BASE ^ a->len
                     58:         *      BASE ^ (b->len - 2) < -b <= BASE ^ (b->len - 1)
                     59:         *
                     60:         *      do divide.
                     61:         */
                     62: 
                     63:        if (a->len <= b->len - 2)
                     64:                mcopy(mzero, q);
                     65:        else
                     66:                longd(a, b, q);
                     67: 
                     68:        /* adjust signs */
                     69:        if (apos ? !bpos : bpos) {
                     70:                mneg(q, q);
                     71:                mneg(a, r);
                     72:        } else
                     73:                mcopy(a, r);
                     74: 
                     75:        /* throw away garbage */
                     76:        mpfree(al.val);
                     77:        if (bpos)
                     78:                mpfree(bl.val);
                     79: }
                     80: 
                     81: 
                     82: /*
                     83:  *     Shortd divides the mints pointed to by "a" and "b".
                     84:  *     It sets the mints pointed to by "q" and "r" to the quotient
                     85:  *     and remainder respectively.  It assumes that "b" is between
                     86:  *     -BASE and BASE.
                     87:  */
                     88: 
                     89: static void
                     90: shortd(a, b, q, r)
                     91: register mint *a, *b, *q, *r;
                     92: {
                     93:        int rem;
                     94:        int denom;
                     95: 
                     96:        assert(b->len <= 2);
                     97:        if (ispos(b)) {
                     98:                denom = b->val[0];
                     99:                if (b->len != 1 && denom == 0)
                    100:                        denom = BASE;
                    101:        } else
                    102:                denom = b->val[0] - BASE;
                    103:        assert(-BASE <= denom && denom <= BASE);
                    104:        sdiv(a, denom, q, &rem);
                    105:        mitom(rem, r);
                    106: }
                    107: 
                    108: 
                    109: /*
                    110:  *     Longd does the actual long divide.  It sets "q" and "a" to
                    111:  *     the quotient and remainder (respectively) of "a" / (- "b").
                    112:  *     It assumes the following:
                    113:  *       1. "b" is negative
                    114:  *       2. "a" is positive
                    115:  *       3. "a" is a destroyable copy
                    116:  *       4. ("a"->len + 2) > ("b"->len) >= 3
                    117:  */
                    118: 
                    119: static void
                    120: longd(a, b, q)
                    121: register mint *a, *b;
                    122: mint *q;
                    123: {
                    124:        register char *rp;
                    125:        unsigned shift;
                    126:        int tden;
                    127:        unsigned tbias;
                    128:        mint res;
                    129: 
                    130: 
                    131:        /*
                    132:         *      For "a" we have the range
                    133:         *              (BASE - 1) * BASE ^ (a->len - 1) > a
                    134:         *                      a >= (BASE - 1) * BASE ^ (a->len - 2)
                    135:         *      and for "b" we want
                    136:         *              tden * BASE ^ tbias >= -b > (tden - 1) * BASE ^ tbias
                    137:         */
                    138: 
                    139:        tden = est(b);
                    140:        tbias = b->len - 3;
                    141: 
                    142:        assert(a->len >= tbias + 2);
                    143:        res.len = a->len - tbias;
                    144:        res.val = (char *)mpalc(res.len);
                    145:        rp = &res.val[res.len - 1];
                    146:        *rp-- = 0;
                    147:        shift = a->len - (tbias + 2);
                    148: 
                    149:        do {
                    150:                *rp = guess(tden, tbias + shift, a);
                    151:                msma(b, *rp, shift, a);
                    152:                if (snc(b, shift, a)) {
                    153:                        ++*rp;
                    154:                        msma(b, 1, shift, a);
                    155:                }
                    156:                --rp;
                    157:        } while (shift-- != 0);
                    158:        norm(a);
                    159:        norm(&res);
                    160:        mpfree(q->val);
                    161:        *q = res;
                    162: }
                    163: 
                    164: 
                    165: 
                    166: 
                    167: /*
                    168:  *     Est estimates the mint pointed to by "a".  Its result
                    169:  *     satisfies the following:
                    170:  *             1.  result * BASE ^ (a->len - 3) >= -a
                    171:  *                     && -a > (result - 1) * BASE ^ (a->len - 3)
                    172:  *             2.  BASE ^ 2 >= mant > BASE
                    173:  *     Note that "a" is assumed to be negative and have length atleast
                    174:  *     three.
                    175:  */
                    176: static int
                    177: est(a)
                    178: register mint *a;
                    179: {
                    180:        register int result;
                    181: 
                    182:        assert(!ispos(a) && a->len >= 3);
                    183:        result = (NEFL - a->val[a->len - 2]) << L2BASE;
                    184:        result += NEFL - a->val[a->len - 3] + 1;
                    185:        assert(BASE * BASE >= result && result > BASE);
                    186:        return (result);
                    187: }
                    188: 
                    189: 
                    190: /*
                    191:  *     Guess returns an integer which is the integral part of
                    192:  *             "a" / ("den" * BASE ^ "shift")
                    193:  *     Note that it is assumed that the following hold:
                    194:  *             1.  "a" is positive.
                    195:  *             2.  BASE ^ 2 >= "den" > BASE
                    196:  *             3.  the quotient is a single "digit" (ie. NEFL > quotient >= 0)
                    197:  */
                    198: 
                    199: static int
                    200: guess(den, shift, a)
                    201: int den;
                    202: unsigned shift;
                    203: mint *a;
                    204: {
                    205:        register char *ap = &a->val[a->len - 1];
                    206:        long result;
                    207: 
                    208:        if (*ap == 0)
                    209:                --ap;
                    210:        assert(ap + 1 - a->val <= shift + 3);
                    211:        if (ap + 1 - a->val < shift + 2)
                    212:                return (0);
                    213:        result = (ap[0] << L2BASE) + ap[-1];
                    214:        if (ap + 1 - a->val == shift + 3)
                    215:                result = (result << L2BASE) + ap[-2];
                    216:        assert(result < den * (long)BASE);
                    217:        return (result / den);
                    218: }
                    219: 
                    220: 
                    221: /*
                    222:  *     Snc does a shift-negate-compare.  Specifically, it assumes that
                    223:  *     "b" is negative, "a" is positive and it returns wether or not
                    224:  *             a  >=  -b * BASE ^ shift
                    225:  *     (ie. a + b * BASE ^ shift is positive (ie. >= 0).)
                    226:  */
                    227: 
                    228: static
                    229: snc(b, shift, a)
                    230: mint *a, *b;
                    231: unsigned shift;
                    232: {
                    233:        register char *ap;
                    234:        register char *bp;
                    235:        register char *limit;
                    236:        int aleng, bleng;
                    237:        int temp;
                    238: 
                    239:        /*
                    240:         * correct length of a
                    241:         */
                    242:        limit = a->val;
                    243:        for (ap = &limit[a->len - 1]; *ap == 0 && ap > limit; --ap)
                    244:                ;
                    245:        a->len = ap - limit + 1;
                    246:        if (*ap == NEFL)
                    247:                ++a->len;
                    248:        aleng = ap - limit + 1;
                    249:        bleng = b->len + shift - 1;
                    250: 
                    251:        /*
                    252:         *      BASE ^ aleng  >  a  >=  BASE ^ (aleng - 1)
                    253:         *      BASE ^ (b->len - 1)  >=  -b  >  BASE ^ (b->len - 2)
                    254:         *      so multiplying by BASE ^ shift gives
                    255:         *      BASE ^ bleng  >=  -b * BASE ^ shift  >  BASE ^ (bleng - 1)
                    256:         *      This means that
                    257:         *      IF      bleng  >  aleng
                    258:         *      THEN    bleng - 1  >=  aleng
                    259:         *      SO      -b * BASE ^ shift  >  BASE ^ (bleng - 1)
                    260:         *                                 >= BASE ^ aleng
                    261:         *                                 >  a
                    262:         *      and thus we return FALSE.
                    263:         *      Also we have
                    264:         *      IF      aleng  >  bleng
                    265:         *      THEN    aleng - 1  >=  bleng
                    266:         *      SO      a  >=  BASE ^ (aleng - 1)
                    267:         *                 >=  BASE ^ bleng
                    268:         *                 >=  -b * BASE ^ shift
                    269:         *      and thus we return TRUE.
                    270:         *      Finally
                    271:         *      If aleng = bleng then the two numbers line up and
                    272:         *      it is just a matter of returning wether or not their
                    273:         *      sum would cause a carry.
                    274:         */
                    275:        if (aleng != bleng)
                    276:                return (aleng > bleng);
                    277:        limit = b->val;
                    278:        for (bp = &limit[b->len - 2]; bp >= limit; --bp, --ap) {
                    279:                temp = *ap + *bp;
                    280:                if (temp >= BASE)
                    281:                        return (TRUE);
                    282:                if (temp < NEFL)
                    283:                        return (FALSE);
                    284:        }
                    285:        return (FALSE);
                    286: }

unix.superglobalmegacorp.com

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