|
|
1.1 root 1: /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
2:
3: /*
4: $Header: b1nuI.c,v 1.4 85/08/22 16:51:13 timo Exp $
5: */
6:
7: /* Multi-precision integer arithmetic */
8:
9: #include "b.h"
10: #include "b1obj.h"
11: #include "b1num.h"
12: #include "b0con.h"
13: #include "b3err.h"
14:
15: /*
16: * Number representation:
17: * ======================
18: *
19: * (Think of BASE = 10 for ordinary decimal notation.)
20: * A number is a sequence of N "digits" b1, b2, ..., bN
21: * where each bi is in {0..BASE-1}, except for negative numbers,
22: * where bN = -1.
23: * The number represented by b1, ..., bN is
24: * b1*BASE**(N-1) + b2*BASE**(N-2) + ... + bN .
25: * The base BASE is chosen so that multiplication of two positive
26: * integers up to BASE-1 can be multiplied exactly using double
27: * precision floating point arithmetic.
28: * Also it must be possible to add two long integers between
29: * -BASE and +BASE (exclusive), giving a result between -2BASE and
30: * +2BASE.
31: * BASE must be even (so we can easily decide whether the whole
32: * number is even), and positive (to avoid all kinds of other trouble).
33: * Presently, it is restricted to a power of 10 by the I/O-conversion
34: * routines (file "b1nuC.c").
35: *
36: * Canonical representation:
37: * bN is never zero (for the number zero itself, N is zero).
38: * If bN is -1, b[N-1] is never BASE-1 .
39: * All operands are assumed te be in canonical representation.
40: * Routine "int_canon" brings a number in canonical representation.
41: *
42: * Mapping to C objects:
43: * A "digit" is an integer of type "digit", probably an "int".
44: * A number is represented as a "B-integer", i.e. something
45: * of type "integer" (which is actually a pointer to some struct).
46: * The number of digits N is extracted through the macro Length(v).
47: * The i-th digit is extracted through the macro Digit(v,N-i).
48: * (So in C, we count in a backwards direction from 0 ... n-1 !)
49: * A number is created through a call to grab_num(N), which sets
50: * N zero digits (thus not in canonical form!).
51: */
52:
53:
54: /*
55: * Bring an integer into canonical form.
56: * Make a SmallInt if at all possible.
57: * NB: Work done by int_canon is duplicated by mk_integer for optimization;
58: * if the strategy here changes, look at mk_integer, too!
59: */
60:
61: Visible integer int_canon(v) integer v; {
62: register int i;
63:
64: if (IsSmallInt(v)) return v;
65:
66: for (i = Length(v) - 1; i >= 0 && Digit(v,i) == 0; --i)
67: ;
68:
69: if (i < 0) {
70: release((value) v);
71: return int_0;
72: }
73:
74: if (i == 0) {
75: digit dig = Digit(v,0);
76: release((value) v);
77: return (integer) MkSmallInt(dig);
78: }
79:
80: if (i > 0 && Digit(v,i) == -1) {
81: while (i > 0 && Digit(v, i-1) == BASE-1) --i;
82: if (i == 0) {
83: release((value) v);
84: return (integer) MkSmallInt(-1);
85: }
86: if (i == 1) {
87: digit dig = Digit(v,0) - BASE;
88: release((value) v);
89: return (integer) MkSmallInt(dig);
90: }
91: Digit(v,i) = -1;
92: }
93:
94: if (i+1 < Length(v)) return (integer) regrab_num((value) v, i+1);
95:
96: return v;
97: }
98:
99:
100: /* General add/subtract subroutine */
101:
102: typedef double twodigit; /* Might be long on 16 bit machines */
103: /* Should be in b0con.h */
104:
105: Hidden twodigit fmodulo(x, y) twodigit x, y; {
106: return x - y * (twodigit) floor((double)x / (double)y);
107: }
108:
109: Visible Procedure dig_gadd(to, nto, from, nfrom, ffactor)
110: digit *to, *from; intlet nto, nfrom; digit ffactor; {
111: twodigit carry= 0;
112: twodigit factor= ffactor;
113: digit save;
114:
115: nto -= nfrom;
116: if (nto < 0)
117: syserr(MESS(1000, "dig_gadd: nto < nfrom"));
118: for (; nfrom > 0; ++to, ++from, --nfrom) {
119: carry += *to + *from * factor;
120: *to= save= fmodulo(carry, (twodigit)BASE);
121: carry= (carry-save) / BASE;
122: }
123: for (; nto > 0; ++to, --nto) {
124: if (carry == 0)
125: return;
126: carry += *to;
127: *to= save= fmodulo(carry, (twodigit)BASE);
128: carry= (carry-save) / BASE;
129: }
130: if (carry != 0)
131: to[-1] += carry*BASE; /* Assume it's -1 */
132: }
133:
134:
135: /* Sum or difference of two integers */
136: /* Should have its own version of dig-gadd without double precision */
137:
138: Visible integer int_gadd(v, w, factor) integer v, w; intlet factor; {
139: struct integer vv, ww;
140: integer s;
141: int len, lenv, i;
142:
143: FreezeSmallInt(v, vv);
144: FreezeSmallInt(w, ww);
145: lenv= len= Length(v);
146: if (Length(w) > len)
147: len= Length(w);
148: ++len;
149: s= (integer) grab_num(len);
150: for (i= 0; i < lenv; ++i)
151: Digit(s, i)= Digit(v, i);
152: for (; i < len; ++i)
153: Digit(s, i)= 0;
154: dig_gadd(&Digit(s, 0), len, &Digit(w, 0), Length(w), (digit)factor);
155: return int_canon(s);
156: }
157:
158:
159: /* Product of two integers */
160:
161: Visible integer int_prod(v, w) integer v, w; {
162: int i;
163: integer a;
164: struct integer vv, ww;
165:
166: if (v == int_0 || w == int_0) return int_0;
167: if (v == int_1) return (integer) Copy(w);
168: if (w == int_1) return (integer) Copy(v);
169:
170: FreezeSmallInt(v, vv);
171: FreezeSmallInt(w, ww);
172:
173: a = (integer) grab_num(Length(v) + Length(w));
174:
175: for (i= Length(a)-1; i >= 0; --i)
176: Digit(a, i)= 0;
177: for (i = 0; i < Length(v) && !interrupted; ++i)
178: dig_gadd(&Digit(a, i), Length(w)+1, &Digit(w, 0), Length(w),
179: Digit(v, i));
180:
181: return int_canon(a);
182: }
183:
184:
185: /* Compare two integers */
186:
187: Visible relation int_comp(v, w) integer v, w; {
188: int sv, sw;
189: register int i;
190: struct integer vv, ww;
191:
192: /* 1. Compare pointers and equal SmallInts */
193: if (v == w) return 0;
194:
195: /* 1a. Handle SmallInts */
196: if (IsSmallInt(v) && IsSmallInt(w))
197: return SmallIntVal(v) - SmallIntVal(w);
198: FreezeSmallInt(v, vv);
199: FreezeSmallInt(w, ww);
200:
201: /* 2. Extract signs */
202: sv = Length(v)==0 ? 0 : Digit(v,Length(v)-1)<0 ? -1 : 1;
203: sw = Length(w)==0 ? 0 : Digit(w,Length(w)-1)<0 ? -1 : 1;
204:
205: /* 3. Compare signs */
206: if (sv != sw) return (sv>sw) - (sv<sw);
207:
208: /* 4. Compare sizes */
209: if (Length(v) != Length(w))
210: return sv * ( (Length(v)>Length(w)) - (Length(v)<Length(w)) );
211:
212: /* 5. Compare individual digits */
213: for (i = Length(v)-1; i >= 0 && Digit(v,i) == Digit(w,i); --i)
214: ;
215:
216: /* 6. All digits equal? */
217: if (i < 0) return 0; /* Yes */
218:
219: /* 7. Compare leftmost different digits */
220: if (Digit(v,i) < Digit(w,i)) return -1;
221:
222: return 1;
223: }
224:
225:
226: /* Construct an integer out of a floating point number */
227:
228: #define GRAN 8 /* Granularity used when requesting more storage */
229: /* MOVE TO MEM! */
230: Visible integer mk_int(x) double x; {
231: register integer a;
232: integer b;
233: register int i, j;
234: int negate;
235:
236: if (MinSmallInt <= x && x <= MaxSmallInt)
237: return (integer) MkSmallInt((int)x);
238:
239: a = (integer) grab_num(1);
240: negate = x < 0 ? 1 : 0;
241: if (negate) x = -x;
242:
243: for (i = 0; x != 0; ++i) {
244: double z = floor(x/BASE);
245: digit save = Modulo((digit)(x-z*BASE), BASE);
246: if (i >= Length(a)) {
247: a = (integer) regrab_num((value) a, Length(a)+GRAN);
248: for (j = Length(a)-1; j > i; --j)
249: Digit(a,j) = 0; /* clear higher digits */
250: }
251: Digit(a,i) = save;
252: x = floor((x-save)/BASE);
253: }
254:
255: if (negate) {
256: b = int_neg(a);
257: release((value) a);
258: return b;
259: }
260:
261: return int_canon(a);
262: }
263:
264: /* Construct an integer out of a C int. Like mk_int, but optimized. */
265:
266: Visible value mk_integer(x) int x; {
267: if (MinSmallInt <= x && x <= MaxSmallInt) return MkSmallInt(x);
268: return (value) mk_int((double)x);
269: }
270:
271:
272: /* Efficiently compute 10**n as a B integer, where n is a C int >= 0 */
273:
274: Visible integer int_tento(n) int n; {
275: integer i;
276: digit msd = 1;
277: if (n < 0) syserr(MESS(1001, "int_tento(-n)"));
278: if (n < tenlogBASE) {
279: while (n != 0) msd *= 10, --n;
280: return (integer) MkSmallInt(msd);
281: }
282: i = (integer) grab_num(1 + (int)(n/tenlogBASE));
283: n %= tenlogBASE;
284: while (n != 0) msd *= 10, --n;
285: Digit(i, Length(i)-1) = msd;
286: return i;
287: }
288:
289: #ifdef NOT_USED
290: /* Approximate ceiling(10 log abs(u/v)), as C int.
291: It only works for v > 0, u, v both integers.
292: The result may be one too large or too small */
293:
294: Visible int scale(u, v) integer u, v; {
295: int s;
296: double z;
297: struct integer uu, vv;
298:
299: if (Msd(v) <= 0) syserr(MESS(1002, "scale(u,v<=0)"));
300: if (u == int_0) return 0; /* `Don't care' case */
301: FreezeSmallInt(u, uu);
302: FreezeSmallInt(v, vv);
303: s = (Length(u) - Length(v)) * tenlogBASE;
304: if (Digit(u, Length(u)-1) >= 0) z = Digit(u, Length(u)-1);
305: else {
306: s -= tenlogBASE;
307: if (Length(u) == 1) z = 1;
308: else z = BASE - Digit(u, Length(u)-2);
309: }
310: z /= Digit(v, Length(v)-1);
311: while (z >= 10) z /= 10, ++s;
312: while (z < 1) z *= 10, --s;
313: return s;
314: }
315: #endif NOT_USED
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.