|
1 /* glplib01.c (bignum arithmetic) */ |
|
2 |
|
3 /*********************************************************************** |
|
4 * This code is part of GLPK (GNU Linear Programming Kit). |
|
5 * |
|
6 * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, |
|
7 * 2009, 2010 Andrew Makhorin, Department for Applied Informatics, |
|
8 * Moscow Aviation Institute, Moscow, Russia. All rights reserved. |
|
9 * E-mail: <mao@gnu.org>. |
|
10 * |
|
11 * GLPK is free software: you can redistribute it and/or modify it |
|
12 * under the terms of the GNU General Public License as published by |
|
13 * the Free Software Foundation, either version 3 of the License, or |
|
14 * (at your option) any later version. |
|
15 * |
|
16 * GLPK is distributed in the hope that it will be useful, but WITHOUT |
|
17 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
|
18 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public |
|
19 * License for more details. |
|
20 * |
|
21 * You should have received a copy of the GNU General Public License |
|
22 * along with GLPK. If not, see <http://www.gnu.org/licenses/>. |
|
23 ***********************************************************************/ |
|
24 |
|
25 #include "glpenv.h" |
|
26 #include "glplib.h" |
|
27 |
|
28 /*********************************************************************** |
|
29 * Two routines below are intended to multiply and divide unsigned |
|
30 * integer numbers of arbitrary precision. |
|
31 * |
|
32 * The routines assume that an unsigned integer number is represented in |
|
33 * the positional numeral system with the base 2^16 = 65536, i.e. each |
|
34 * "digit" of the number is in the range [0, 65535] and represented as |
|
35 * a 16-bit value of the unsigned short type. In other words, a number x |
|
36 * has the following representation: |
|
37 * |
|
38 * n-1 |
|
39 * x = sum d[j] * 65536^j, |
|
40 * j=0 |
|
41 * |
|
42 * where n is the number of places (positions), and d[j] is j-th "digit" |
|
43 * of x, 0 <= d[j] <= 65535. |
|
44 ***********************************************************************/ |
|
45 |
|
46 /*********************************************************************** |
|
47 * NAME |
|
48 * |
|
49 * bigmul - multiply unsigned integer numbers of arbitrary precision |
|
50 * |
|
51 * SYNOPSIS |
|
52 * |
|
53 * #include "glplib.h" |
|
54 * void bigmul(int n, int m, unsigned short x[], unsigned short y[]); |
|
55 * |
|
56 * DESCRIPTION |
|
57 * |
|
58 * The routine bigmul multiplies unsigned integer numbers of arbitrary |
|
59 * precision. |
|
60 * |
|
61 * n is the number of digits of multiplicand, n >= 1; |
|
62 * |
|
63 * m is the number of digits of multiplier, m >= 1; |
|
64 * |
|
65 * x is an array containing digits of the multiplicand in elements |
|
66 * x[m], x[m+1], ..., x[n+m-1]. Contents of x[0], x[1], ..., x[m-1] are |
|
67 * ignored on entry. |
|
68 * |
|
69 * y is an array containing digits of the multiplier in elements y[0], |
|
70 * y[1], ..., y[m-1]. |
|
71 * |
|
72 * On exit digits of the product are stored in elements x[0], x[1], ..., |
|
73 * x[n+m-1]. The array y is not changed. */ |
|
74 |
|
75 void bigmul(int n, int m, unsigned short x[], unsigned short y[]) |
|
76 { int i, j; |
|
77 unsigned int t; |
|
78 xassert(n >= 1); |
|
79 xassert(m >= 1); |
|
80 for (j = 0; j < m; j++) x[j] = 0; |
|
81 for (i = 0; i < n; i++) |
|
82 { if (x[i+m]) |
|
83 { t = 0; |
|
84 for (j = 0; j < m; j++) |
|
85 { t += (unsigned int)x[i+m] * (unsigned int)y[j] + |
|
86 (unsigned int)x[i+j]; |
|
87 x[i+j] = (unsigned short)t; |
|
88 t >>= 16; |
|
89 } |
|
90 x[i+m] = (unsigned short)t; |
|
91 } |
|
92 } |
|
93 return; |
|
94 } |
|
95 |
|
96 /*********************************************************************** |
|
97 * NAME |
|
98 * |
|
99 * bigdiv - divide unsigned integer numbers of arbitrary precision |
|
100 * |
|
101 * SYNOPSIS |
|
102 * |
|
103 * #include "glplib.h" |
|
104 * void bigdiv(int n, int m, unsigned short x[], unsigned short y[]); |
|
105 * |
|
106 * DESCRIPTION |
|
107 * |
|
108 * The routine bigdiv divides one unsigned integer number of arbitrary |
|
109 * precision by another with the algorithm described in [1]. |
|
110 * |
|
111 * n is the difference between the number of digits of dividend and the |
|
112 * number of digits of divisor, n >= 0. |
|
113 * |
|
114 * m is the number of digits of divisor, m >= 1. |
|
115 * |
|
116 * x is an array containing digits of the dividend in elements x[0], |
|
117 * x[1], ..., x[n+m-1]. |
|
118 * |
|
119 * y is an array containing digits of the divisor in elements y[0], |
|
120 * y[1], ..., y[m-1]. The highest digit y[m-1] must be non-zero. |
|
121 * |
|
122 * On exit n+1 digits of the quotient are stored in elements x[m], |
|
123 * x[m+1], ..., x[n+m], and m digits of the remainder are stored in |
|
124 * elements x[0], x[1], ..., x[m-1]. The array y is changed but then |
|
125 * restored. |
|
126 * |
|
127 * REFERENCES |
|
128 * |
|
129 * 1. D. Knuth. The Art of Computer Programming. Vol. 2: Seminumerical |
|
130 * Algorithms. Stanford University, 1969. */ |
|
131 |
|
132 void bigdiv(int n, int m, unsigned short x[], unsigned short y[]) |
|
133 { int i, j; |
|
134 unsigned int t; |
|
135 unsigned short d, q, r; |
|
136 xassert(n >= 0); |
|
137 xassert(m >= 1); |
|
138 xassert(y[m-1] != 0); |
|
139 /* special case when divisor has the only digit */ |
|
140 if (m == 1) |
|
141 { d = 0; |
|
142 for (i = n; i >= 0; i--) |
|
143 { t = ((unsigned int)d << 16) + (unsigned int)x[i]; |
|
144 x[i+1] = (unsigned short)(t / y[0]); |
|
145 d = (unsigned short)(t % y[0]); |
|
146 } |
|
147 x[0] = d; |
|
148 goto done; |
|
149 } |
|
150 /* multiply dividend and divisor by a normalizing coefficient in |
|
151 order to provide the condition y[m-1] >= base / 2 */ |
|
152 d = (unsigned short)(0x10000 / ((unsigned int)y[m-1] + 1)); |
|
153 if (d == 1) |
|
154 x[n+m] = 0; |
|
155 else |
|
156 { t = 0; |
|
157 for (i = 0; i < n+m; i++) |
|
158 { t += (unsigned int)x[i] * (unsigned int)d; |
|
159 x[i] = (unsigned short)t; |
|
160 t >>= 16; |
|
161 } |
|
162 x[n+m] = (unsigned short)t; |
|
163 t = 0; |
|
164 for (j = 0; j < m; j++) |
|
165 { t += (unsigned int)y[j] * (unsigned int)d; |
|
166 y[j] = (unsigned short)t; |
|
167 t >>= 16; |
|
168 } |
|
169 } |
|
170 /* main loop */ |
|
171 for (i = n; i >= 0; i--) |
|
172 { /* estimate and correct the current digit of quotient */ |
|
173 if (x[i+m] < y[m-1]) |
|
174 { t = ((unsigned int)x[i+m] << 16) + (unsigned int)x[i+m-1]; |
|
175 q = (unsigned short)(t / (unsigned int)y[m-1]); |
|
176 r = (unsigned short)(t % (unsigned int)y[m-1]); |
|
177 if (q == 0) goto putq; else goto test; |
|
178 } |
|
179 q = 0; |
|
180 r = x[i+m-1]; |
|
181 decr: q--; /* if q = 0 then q-- = 0xFFFF */ |
|
182 t = (unsigned int)r + (unsigned int)y[m-1]; |
|
183 r = (unsigned short)t; |
|
184 if (t > 0xFFFF) goto msub; |
|
185 test: t = (unsigned int)y[m-2] * (unsigned int)q; |
|
186 if ((unsigned short)(t >> 16) > r) goto decr; |
|
187 if ((unsigned short)(t >> 16) < r) goto msub; |
|
188 if ((unsigned short)t > x[i+m-2]) goto decr; |
|
189 msub: /* now subtract divisor multiplied by the current digit of |
|
190 quotient from the current dividend */ |
|
191 if (q == 0) goto putq; |
|
192 t = 0; |
|
193 for (j = 0; j < m; j++) |
|
194 { t += (unsigned int)y[j] * (unsigned int)q; |
|
195 if (x[i+j] < (unsigned short)t) t += 0x10000; |
|
196 x[i+j] -= (unsigned short)t; |
|
197 t >>= 16; |
|
198 } |
|
199 if (x[i+m] >= (unsigned short)t) goto putq; |
|
200 /* perform correcting addition, because the current digit of |
|
201 quotient is greater by one than its correct value */ |
|
202 q--; |
|
203 t = 0; |
|
204 for (j = 0; j < m; j++) |
|
205 { t += (unsigned int)x[i+j] + (unsigned int)y[j]; |
|
206 x[i+j] = (unsigned short)t; |
|
207 t >>= 16; |
|
208 } |
|
209 putq: /* store the current digit of quotient */ |
|
210 x[i+m] = q; |
|
211 } |
|
212 /* divide divisor and remainder by the normalizing coefficient in |
|
213 order to restore their original values */ |
|
214 if (d > 1) |
|
215 { t = 0; |
|
216 for (i = m-1; i >= 0; i--) |
|
217 { t = (t << 16) + (unsigned int)x[i]; |
|
218 x[i] = (unsigned short)(t / (unsigned int)d); |
|
219 t %= (unsigned int)d; |
|
220 } |
|
221 t = 0; |
|
222 for (j = m-1; j >= 0; j--) |
|
223 { t = (t << 16) + (unsigned int)y[j]; |
|
224 y[j] = (unsigned short)(t / (unsigned int)d); |
|
225 t %= (unsigned int)d; |
|
226 } |
|
227 } |
|
228 done: return; |
|
229 } |
|
230 |
|
231 /**********************************************************************/ |
|
232 |
|
233 #if 0 |
|
234 #include <assert.h> |
|
235 #include <stdio.h> |
|
236 #include <stdlib.h> |
|
237 #include "glprng.h" |
|
238 |
|
239 #define N_MAX 7 |
|
240 /* maximal number of digits in multiplicand */ |
|
241 |
|
242 #define M_MAX 5 |
|
243 /* maximal number of digits in multiplier */ |
|
244 |
|
245 #define N_TEST 1000000 |
|
246 /* number of tests */ |
|
247 |
|
248 int main(void) |
|
249 { RNG *rand; |
|
250 int d, j, n, m, test; |
|
251 unsigned short x[N_MAX], y[M_MAX], z[N_MAX+M_MAX]; |
|
252 rand = rng_create_rand(); |
|
253 for (test = 1; test <= N_TEST; test++) |
|
254 { /* x[0,...,n-1] := multiplicand */ |
|
255 n = 1 + rng_unif_rand(rand, N_MAX-1); |
|
256 assert(1 <= n && n <= N_MAX); |
|
257 for (j = 0; j < n; j++) |
|
258 { d = rng_unif_rand(rand, 65536); |
|
259 assert(0 <= d && d <= 65535); |
|
260 x[j] = (unsigned short)d; |
|
261 } |
|
262 /* y[0,...,m-1] := multiplier */ |
|
263 m = 1 + rng_unif_rand(rand, M_MAX-1); |
|
264 assert(1 <= m && m <= M_MAX); |
|
265 for (j = 0; j < m; j++) |
|
266 { d = rng_unif_rand(rand, 65536); |
|
267 assert(0 <= d && d <= 65535); |
|
268 y[j] = (unsigned short)d; |
|
269 } |
|
270 if (y[m-1] == 0) y[m-1] = 1; |
|
271 /* z[0,...,n+m-1] := x * y */ |
|
272 for (j = 0; j < n; j++) z[m+j] = x[j]; |
|
273 bigmul(n, m, z, y); |
|
274 /* z[0,...,m-1] := z mod y, z[m,...,n+m-1] := z div y */ |
|
275 bigdiv(n, m, z, y); |
|
276 /* z mod y must be 0 */ |
|
277 for (j = 0; j < m; j++) assert(z[j] == 0); |
|
278 /* z div y must be x */ |
|
279 for (j = 0; j < n; j++) assert(z[m+j] == x[j]); |
|
280 } |
|
281 fprintf(stderr, "%d tests successfully passed\n", N_TEST); |
|
282 rng_delete_rand(rand); |
|
283 return 0; |
|
284 } |
|
285 #endif |
|
286 |
|
287 /* eof */ |