Annotation of 43BSD/contrib/B/src/bint/b1nuQ.c, revision 1.1

1.1     ! root        1: /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
        !             2: 
        !             3: /*
        !             4:   $Header: b1nuQ.c,v 1.4 85/08/22 16:51:40 timo Exp $
        !             5: */
        !             6: 
        !             7: #include "b.h"
        !             8: #include "b1obj.h"
        !             9: #include "b0con.h"
        !            10: #include "b1num.h"
        !            11: 
        !            12: 
        !            13: /* Product of integer and single "digit" */
        !            14: 
        !            15: Visible integer int1mul(v, n1) integer v; digit n1; {
        !            16:        integer a;
        !            17:        digit save, bigcarry, carry = 0;
        !            18:        double z, zz, n = n1;
        !            19:        register int i;
        !            20:        struct integer vv;
        !            21: 
        !            22:        FreezeSmallInt(v, vv);
        !            23: 
        !            24:        a = (integer) grab_num(Length(v)+2);
        !            25: 
        !            26:        for (i = 0; i < Length(v); ++i) {
        !            27:                z = Digit(v,i) * n;
        !            28:                bigcarry = zz = floor(z/BASE);
        !            29:                carry += z - zz*BASE;
        !            30:                Digit(a,i) = save = Modulo(carry, BASE);
        !            31:                carry = (carry-save)/BASE + bigcarry;
        !            32:        }
        !            33: 
        !            34:        Digit(a,i) = save = Modulo(carry, BASE);
        !            35:        Digit(a,i+1) = (carry-save)/BASE;
        !            36: 
        !            37:        return int_canon(a);
        !            38: }
        !            39: 
        !            40: 
        !            41: /* Quotient of positive integer and single "digit" > 0 */
        !            42: 
        !            43: Hidden integer int1div(v, n1, prem) integer v; digit n1, *prem; {
        !            44:        integer q;
        !            45:        double r_over_n, r = 0, n = n1;
        !            46:        register int i;
        !            47:        struct integer vv;
        !            48: 
        !            49:        FreezeSmallInt(v, vv);
        !            50: 
        !            51:        q = (integer) grab_num(Length(v));
        !            52:        for (i = Length(v)-1; i >= 0; --i) {
        !            53:                r = r*BASE + Digit(v,i);
        !            54:                Digit(q,i) = r_over_n = floor(r/n);
        !            55:                r -= r_over_n * n;
        !            56:        }
        !            57:        if (prem)
        !            58:                *prem = r;
        !            59:        return int_canon(q);
        !            60: }
        !            61: 
        !            62: 
        !            63: /* Long division routine, gives access to division algorithm. */
        !            64: 
        !            65: Visible digit int_ldiv(v1, w1, pquot, prem) integer v1, w1, *pquot, *prem; {
        !            66:        integer a;
        !            67:        int sign = 1, rel_v = 0, rel_w = 0;
        !            68:        digit div, rem;
        !            69:        struct integer vv1, ww1;
        !            70: 
        !            71:        if (w1 == int_0) syserr(MESS(1100, "zero division (int_ldiv)"));
        !            72: 
        !            73:        /* Make v, w positive */
        !            74:        if (Msd(v1) < 0) {
        !            75:                sign = -1;
        !            76:                ++rel_v;
        !            77:                v1 = int_neg(v1);
        !            78:        }
        !            79: 
        !            80:        if (Msd(w1) < 0) {
        !            81:                sign *= -1;
        !            82:                ++rel_w;
        !            83:                w1 = int_neg(w1);
        !            84:        }
        !            85:        
        !            86:        FreezeSmallInt(v1, vv1);
        !            87:        FreezeSmallInt(w1, ww1);
        !            88: 
        !            89:        div = sign;
        !            90: 
        !            91:        /* Check v << w or single-digit w */
        !            92:        if (Length(v1) < Length(w1)
        !            93:                || Length(v1) == Length(w1)
        !            94:                        && Digit(v1, Length(v1)-1) < Digit(w1, Length(w1)-1)) {
        !            95:                a = int_0;
        !            96:                if (prem) {
        !            97:                        if (v1 == &vv1) *prem= (integer) MkSmallInt(Digit(v1,0));
        !            98:                        else *prem = (integer) Copy(v1);
        !            99:                }
        !           100:        }
        !           101:        else if (Length(w1) == 1) {
        !           102:                /* Single-precision division */
        !           103:                a = int1div(v1, Digit(w1,0), &rem);
        !           104:                if (prem) *prem = mk_int((double)rem);
        !           105:        }
        !           106:        else {
        !           107:                /* Multi-precision division */
        !           108:                /* Cf. Knuth II Sec. 4.3.1. Algorithm D */
        !           109:                /* Note that we count in the reverse direction (not easier!) */
        !           110: 
        !           111:                double z, zz;
        !           112:                digit carry, save, bigcarry;
        !           113:                double q, d = BASE/(Digit(w1, Length(w1)-1)+1);
        !           114:                register int i, j, k;
        !           115:                integer v, w;
        !           116:                digit vj;
        !           117: 
        !           118:                /* Normalize: make Msd(w) >= BASE/2 by multiplying
        !           119:                   both v and w by d */
        !           120: 
        !           121:                v = int1mul(v1, (digit)d);
        !           122:                        /* v is used as accumulator, must make a copy */
        !           123:                        /* v cannot be int_1 */
        !           124:                        /* (then it would be one of the cases above) */
        !           125: 
        !           126:                if (d == 1) w = (integer) Copy(w1);
        !           127:                else w = int1mul(w1, (digit)d);
        !           128: 
        !           129:                a = (integer) grab_num(Length(v1)-Length(w)+1);
        !           130: 
        !           131:                /* Division loop */
        !           132: 
        !           133:                for (j = Length(v1), k = Length(a)-1; k >= 0; --j, --k) {
        !           134:                        vj = j >= Length(v) ? 0 : Digit(v,j);
        !           135: 
        !           136:                        /* Find trial digit */
        !           137: 
        !           138:                        if (vj == Digit(w, Length(w)-1)) q = BASE-1;
        !           139:                        else q = floor( ((double)vj*BASE
        !           140:                                        + Digit(v,j-1)) / Digit(w, Length(w)-1) );
        !           141: 
        !           142:                        /* Correct trial digit */
        !           143: 
        !           144:                        while (Digit(w,Length(w)-2) * q >
        !           145:                                ((double)vj*BASE + Digit(v,j-1)
        !           146:                                        - q*Digit(w, Length(w)-1)) *BASE + Digit(v,j-2))
        !           147:                                --q;
        !           148: 
        !           149:                        /* Subtract q*w from v */
        !           150: 
        !           151:                        carry = 0;
        !           152:                        for (i = 0; i < Length(w) && i+k < Length(v); ++i) {
        !           153:                                z = Digit(w,i) * q;
        !           154:                                bigcarry = zz = floor(z/BASE);
        !           155:                                carry += Digit(v,i+k) - z + zz*BASE;
        !           156:                                Digit(v,i+k) =
        !           157:                                        save = Modulo(carry, BASE);
        !           158:                                carry = (carry-save)/BASE - bigcarry;
        !           159:                        }
        !           160: 
        !           161:                        if (i+k < Length(v))
        !           162:                                carry += Digit(v, i+k), Digit(v, i+k) = 0;
        !           163: 
        !           164:                        /* Add back necessary? */
        !           165: 
        !           166:                                /* It is very difficult to find test cases
        !           167:                                   where add back is necessary if BASE is large.
        !           168:                                   Thanks to Arjen Lenstra, we have v=n*n-1, w=n,
        !           169:                                   where n = 8109636009903000000 (the last six
        !           170:                                   digits are not important). */
        !           171: 
        !           172:                        if (carry == 0)         /* No */
        !           173:                                Digit(a,k) = q;
        !           174:                        else {          /* Yes, add back */
        !           175:                                if (carry != -1) syserr(MESS(1101, "int_ldiv internal failure"));
        !           176:                                Digit(a,k) = q-1;
        !           177:                                carry = 0;
        !           178:                                for (i = 0; i < Length(w) && i+k < Length(v); ++i) {
        !           179:                                        carry += Digit(v, i+k) + Digit(w,i);
        !           180:                                        Digit(v,i+k) =
        !           181:                                                save = Modulo(carry, BASE);
        !           182:                                        carry = (carry-save)/BASE;
        !           183:                                }
        !           184:                        }
        !           185:                }       /* End for(j) */
        !           186: 
        !           187:                if (prem) *prem = int_canon(v); /* Store remainder */
        !           188:                else release((value) v);
        !           189:                div = sign*d;   /* Store normalization factor */
        !           190:                release((value) w);
        !           191:                a = int_canon(a);
        !           192:        }
        !           193: 
        !           194:        if (rel_v) release((value) v1);
        !           195:        if (rel_w) release((value) w1);
        !           196: 
        !           197:        if (sign < 0) {
        !           198:                integer temp = a;
        !           199:                a = int_neg(a);
        !           200:                release((value) temp);
        !           201:        }
        !           202: 
        !           203:        if (pquot) *pquot = a;
        !           204:        else release((value) a);
        !           205:        return div;
        !           206: }
        !           207: 
        !           208: 
        !           209: Visible integer int_quot(v, w) integer v, w; {
        !           210:        integer quo;
        !           211:        VOID int_ldiv(v, w, &quo, (integer*)0);
        !           212:        return quo;
        !           213: }
        !           214: 
        !           215: Visible integer int_mod(v, w) integer v, w; {
        !           216:        integer rem;
        !           217:        digit div;
        !           218:        bool flag;
        !           219:        div = int_ldiv(v, w, (integer*)0, &rem); /* Rem. is always positive */
        !           220:        if (rem == int_0)
        !           221:                return rem; /* v mod w = 0 */
        !           222:        flag = (div < 0);
        !           223:        if (flag || Msd(w) < 0) div = -div;
        !           224:        if (div != 1) { /* Divide by div to get proper remainder back */
        !           225:                v = int1div(rem, div, (digit*)0);
        !           226:                release((value) rem);
        !           227:                rem = v;
        !           228:        }
        !           229:        if (flag) { /* Make same sign as w */
        !           230:                if (Msd(w) < 0) v = int_sum(w, rem);
        !           231:                else v = int_diff(w, rem);
        !           232:                release((value) rem);
        !           233:                rem = v;
        !           234:        }
        !           235:        return rem;
        !           236: }

unix.superglobalmegacorp.com

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