Annotation of 43BSD/contrib/B/src/bint/b1nuQ.c, revision 1.1.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.