|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.