Annotation of coherent/d/usr/lib/libmp/mdiv.c, revision 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.