lemon-project-template-glpk
comparison deps/glpk/src/glpgmp.c @ 9:33de93886c88
Import GLPK 4.47
author | Alpar Juttner <alpar@cs.elte.hu> |
---|---|
date | Sun, 06 Nov 2011 20:59:10 +0100 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:ab4342b34a62 |
---|---|
1 /* glpgmp.c */ | |
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, 2011 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 #define _GLPSTD_STDIO | |
26 #include "glpdmp.h" | |
27 #include "glpgmp.h" | |
28 #define xfault xerror | |
29 | |
30 #ifdef HAVE_GMP /* use GNU MP bignum library */ | |
31 | |
32 int gmp_pool_count(void) { return 0; } | |
33 | |
34 void gmp_free_mem(void) { return; } | |
35 | |
36 #else /* use GLPK bignum module */ | |
37 | |
38 static DMP *gmp_pool = NULL; | |
39 static int gmp_size = 0; | |
40 static unsigned short *gmp_work = NULL; | |
41 | |
42 void *gmp_get_atom(int size) | |
43 { if (gmp_pool == NULL) | |
44 gmp_pool = dmp_create_pool(); | |
45 return dmp_get_atom(gmp_pool, size); | |
46 } | |
47 | |
48 void gmp_free_atom(void *ptr, int size) | |
49 { xassert(gmp_pool != NULL); | |
50 dmp_free_atom(gmp_pool, ptr, size); | |
51 return; | |
52 } | |
53 | |
54 int gmp_pool_count(void) | |
55 { if (gmp_pool == NULL) | |
56 return 0; | |
57 else | |
58 return dmp_in_use(gmp_pool).lo; | |
59 } | |
60 | |
61 unsigned short *gmp_get_work(int size) | |
62 { xassert(size > 0); | |
63 if (gmp_size < size) | |
64 { if (gmp_size == 0) | |
65 { xassert(gmp_work == NULL); | |
66 gmp_size = 100; | |
67 } | |
68 else | |
69 { xassert(gmp_work != NULL); | |
70 xfree(gmp_work); | |
71 } | |
72 while (gmp_size < size) gmp_size += gmp_size; | |
73 gmp_work = xcalloc(gmp_size, sizeof(unsigned short)); | |
74 } | |
75 return gmp_work; | |
76 } | |
77 | |
78 void gmp_free_mem(void) | |
79 { if (gmp_pool != NULL) dmp_delete_pool(gmp_pool); | |
80 if (gmp_work != NULL) xfree(gmp_work); | |
81 gmp_pool = NULL; | |
82 gmp_size = 0; | |
83 gmp_work = NULL; | |
84 return; | |
85 } | |
86 | |
87 /*====================================================================*/ | |
88 | |
89 mpz_t _mpz_init(void) | |
90 { /* initialize x, and set its value to 0 */ | |
91 mpz_t x; | |
92 x = gmp_get_atom(sizeof(struct mpz)); | |
93 x->val = 0; | |
94 x->ptr = NULL; | |
95 return x; | |
96 } | |
97 | |
98 void mpz_clear(mpz_t x) | |
99 { /* free the space occupied by x */ | |
100 mpz_set_si(x, 0); | |
101 xassert(x->ptr == NULL); | |
102 /* free the number descriptor */ | |
103 gmp_free_atom(x, sizeof(struct mpz)); | |
104 return; | |
105 } | |
106 | |
107 void mpz_set(mpz_t z, mpz_t x) | |
108 { /* set the value of z from x */ | |
109 struct mpz_seg *e, *ee, *es; | |
110 if (z != x) | |
111 { mpz_set_si(z, 0); | |
112 z->val = x->val; | |
113 xassert(z->ptr == NULL); | |
114 for (e = x->ptr, es = NULL; e != NULL; e = e->next) | |
115 { ee = gmp_get_atom(sizeof(struct mpz_seg)); | |
116 memcpy(ee->d, e->d, 12); | |
117 ee->next = NULL; | |
118 if (z->ptr == NULL) | |
119 z->ptr = ee; | |
120 else | |
121 es->next = ee; | |
122 es = ee; | |
123 } | |
124 } | |
125 return; | |
126 } | |
127 | |
128 void mpz_set_si(mpz_t x, int val) | |
129 { /* set the value of x to val */ | |
130 struct mpz_seg *e; | |
131 /* free existing segments, if any */ | |
132 while (x->ptr != NULL) | |
133 { e = x->ptr; | |
134 x->ptr = e->next; | |
135 gmp_free_atom(e, sizeof(struct mpz_seg)); | |
136 } | |
137 /* assign new value */ | |
138 if (val == 0x80000000) | |
139 { /* long format is needed */ | |
140 x->val = -1; | |
141 x->ptr = e = gmp_get_atom(sizeof(struct mpz_seg)); | |
142 memset(e->d, 0, 12); | |
143 e->d[1] = 0x8000; | |
144 e->next = NULL; | |
145 } | |
146 else | |
147 { /* short format is enough */ | |
148 x->val = val; | |
149 } | |
150 return; | |
151 } | |
152 | |
153 double mpz_get_d(mpz_t x) | |
154 { /* convert x to a double, truncating if necessary */ | |
155 struct mpz_seg *e; | |
156 int j; | |
157 double val, deg; | |
158 if (x->ptr == NULL) | |
159 val = (double)x->val; | |
160 else | |
161 { xassert(x->val != 0); | |
162 val = 0.0; | |
163 deg = 1.0; | |
164 for (e = x->ptr; e != NULL; e = e->next) | |
165 { for (j = 0; j <= 5; j++) | |
166 { val += deg * (double)((int)e->d[j]); | |
167 deg *= 65536.0; | |
168 } | |
169 } | |
170 if (x->val < 0) val = - val; | |
171 } | |
172 return val; | |
173 } | |
174 | |
175 double mpz_get_d_2exp(int *exp, mpz_t x) | |
176 { /* convert x to a double, truncating if necessary (i.e. rounding | |
177 towards zero), and returning the exponent separately; | |
178 the return value is in the range 0.5 <= |d| < 1 and the | |
179 exponent is stored to *exp; d*2^exp is the (truncated) x value; | |
180 if x is zero, the return is 0.0 and 0 is stored to *exp; | |
181 this is similar to the standard C frexp function */ | |
182 struct mpz_seg *e; | |
183 int j, n, n1; | |
184 double val; | |
185 if (x->ptr == NULL) | |
186 val = (double)x->val, n = 0; | |
187 else | |
188 { xassert(x->val != 0); | |
189 val = 0.0, n = 0; | |
190 for (e = x->ptr; e != NULL; e = e->next) | |
191 { for (j = 0; j <= 5; j++) | |
192 { val += (double)((int)e->d[j]); | |
193 val /= 65536.0, n += 16; | |
194 } | |
195 } | |
196 if (x->val < 0) val = - val; | |
197 } | |
198 val = frexp(val, &n1); | |
199 *exp = n + n1; | |
200 return val; | |
201 } | |
202 | |
203 void mpz_swap(mpz_t x, mpz_t y) | |
204 { /* swap the values x and y efficiently */ | |
205 int val; | |
206 void *ptr; | |
207 val = x->val, ptr = x->ptr; | |
208 x->val = y->val, x->ptr = y->ptr; | |
209 y->val = val, y->ptr = ptr; | |
210 return; | |
211 } | |
212 | |
213 static void normalize(mpz_t x) | |
214 { /* normalize integer x that includes removing non-significant | |
215 (leading) zeros and converting to short format, if possible */ | |
216 struct mpz_seg *es, *e; | |
217 /* if the integer is in short format, it remains unchanged */ | |
218 if (x->ptr == NULL) | |
219 { xassert(x->val != 0x80000000); | |
220 goto done; | |
221 } | |
222 xassert(x->val == +1 || x->val == -1); | |
223 /* find the last (most significant) non-zero segment */ | |
224 es = NULL; | |
225 for (e = x->ptr; e != NULL; e = e->next) | |
226 { if (e->d[0] || e->d[1] || e->d[2] || | |
227 e->d[3] || e->d[4] || e->d[5]) es = e; | |
228 } | |
229 /* if all segments contain zeros, the integer is zero */ | |
230 if (es == NULL) | |
231 { mpz_set_si(x, 0); | |
232 goto done; | |
233 } | |
234 /* remove non-significant (leading) zero segments */ | |
235 while (es->next != NULL) | |
236 { e = es->next; | |
237 es->next = e->next; | |
238 gmp_free_atom(e, sizeof(struct mpz_seg)); | |
239 } | |
240 /* convert the integer to short format, if possible */ | |
241 e = x->ptr; | |
242 if (e->next == NULL && e->d[1] <= 0x7FFF && | |
243 !e->d[2] && !e->d[3] && !e->d[4] && !e->d[5]) | |
244 { int val; | |
245 val = (int)e->d[0] + ((int)e->d[1] << 16); | |
246 if (x->val < 0) val = - val; | |
247 mpz_set_si(x, val); | |
248 } | |
249 done: return; | |
250 } | |
251 | |
252 void mpz_add(mpz_t z, mpz_t x, mpz_t y) | |
253 { /* set z to x + y */ | |
254 static struct mpz_seg zero = { { 0, 0, 0, 0, 0, 0 }, NULL }; | |
255 struct mpz_seg dumx, dumy, *ex, *ey, *ez, *es, *ee; | |
256 int k, sx, sy, sz; | |
257 unsigned int t; | |
258 /* if [x] = 0 then [z] = [y] */ | |
259 if (x->val == 0) | |
260 { xassert(x->ptr == NULL); | |
261 mpz_set(z, y); | |
262 goto done; | |
263 } | |
264 /* if [y] = 0 then [z] = [x] */ | |
265 if (y->val == 0) | |
266 { xassert(y->ptr == NULL); | |
267 mpz_set(z, x); | |
268 goto done; | |
269 } | |
270 /* special case when both [x] and [y] are in short format */ | |
271 if (x->ptr == NULL && y->ptr == NULL) | |
272 { int xval = x->val, yval = y->val, zval = x->val + y->val; | |
273 xassert(xval != 0x80000000 && yval != 0x80000000); | |
274 if (!(xval > 0 && yval > 0 && zval <= 0 || | |
275 xval < 0 && yval < 0 && zval >= 0)) | |
276 { mpz_set_si(z, zval); | |
277 goto done; | |
278 } | |
279 } | |
280 /* convert [x] to long format, if necessary */ | |
281 if (x->ptr == NULL) | |
282 { xassert(x->val != 0x80000000); | |
283 if (x->val >= 0) | |
284 { sx = +1; | |
285 t = (unsigned int)(+ x->val); | |
286 } | |
287 else | |
288 { sx = -1; | |
289 t = (unsigned int)(- x->val); | |
290 } | |
291 ex = &dumx; | |
292 ex->d[0] = (unsigned short)t; | |
293 ex->d[1] = (unsigned short)(t >> 16); | |
294 ex->d[2] = ex->d[3] = ex->d[4] = ex->d[5] = 0; | |
295 ex->next = NULL; | |
296 } | |
297 else | |
298 { sx = x->val; | |
299 xassert(sx == +1 || sx == -1); | |
300 ex = x->ptr; | |
301 } | |
302 /* convert [y] to long format, if necessary */ | |
303 if (y->ptr == NULL) | |
304 { xassert(y->val != 0x80000000); | |
305 if (y->val >= 0) | |
306 { sy = +1; | |
307 t = (unsigned int)(+ y->val); | |
308 } | |
309 else | |
310 { sy = -1; | |
311 t = (unsigned int)(- y->val); | |
312 } | |
313 ey = &dumy; | |
314 ey->d[0] = (unsigned short)t; | |
315 ey->d[1] = (unsigned short)(t >> 16); | |
316 ey->d[2] = ey->d[3] = ey->d[4] = ey->d[5] = 0; | |
317 ey->next = NULL; | |
318 } | |
319 else | |
320 { sy = y->val; | |
321 xassert(sy == +1 || sy == -1); | |
322 ey = y->ptr; | |
323 } | |
324 /* main fragment */ | |
325 sz = sx; | |
326 ez = es = NULL; | |
327 if (sx > 0 && sy > 0 || sx < 0 && sy < 0) | |
328 { /* [x] and [y] have identical signs -- addition */ | |
329 t = 0; | |
330 for (; ex || ey; ex = ex->next, ey = ey->next) | |
331 { if (ex == NULL) ex = &zero; | |
332 if (ey == NULL) ey = &zero; | |
333 ee = gmp_get_atom(sizeof(struct mpz_seg)); | |
334 for (k = 0; k <= 5; k++) | |
335 { t += (unsigned int)ex->d[k]; | |
336 t += (unsigned int)ey->d[k]; | |
337 ee->d[k] = (unsigned short)t; | |
338 t >>= 16; | |
339 } | |
340 ee->next = NULL; | |
341 if (ez == NULL) | |
342 ez = ee; | |
343 else | |
344 es->next = ee; | |
345 es = ee; | |
346 } | |
347 if (t) | |
348 { /* overflow -- one extra digit is needed */ | |
349 ee = gmp_get_atom(sizeof(struct mpz_seg)); | |
350 ee->d[0] = 1; | |
351 ee->d[1] = ee->d[2] = ee->d[3] = ee->d[4] = ee->d[5] = 0; | |
352 ee->next = NULL; | |
353 xassert(es != NULL); | |
354 es->next = ee; | |
355 } | |
356 } | |
357 else | |
358 { /* [x] and [y] have different signs -- subtraction */ | |
359 t = 1; | |
360 for (; ex || ey; ex = ex->next, ey = ey->next) | |
361 { if (ex == NULL) ex = &zero; | |
362 if (ey == NULL) ey = &zero; | |
363 ee = gmp_get_atom(sizeof(struct mpz_seg)); | |
364 for (k = 0; k <= 5; k++) | |
365 { t += (unsigned int)ex->d[k]; | |
366 t += (0xFFFF - (unsigned int)ey->d[k]); | |
367 ee->d[k] = (unsigned short)t; | |
368 t >>= 16; | |
369 } | |
370 ee->next = NULL; | |
371 if (ez == NULL) | |
372 ez = ee; | |
373 else | |
374 es->next = ee; | |
375 es = ee; | |
376 } | |
377 if (!t) | |
378 { /* |[x]| < |[y]| -- result in complement coding */ | |
379 sz = - sz; | |
380 t = 1; | |
381 for (ee = ez; ee != NULL; ee = ee->next) | |
382 for (k = 0; k <= 5; k++) | |
383 { t += (0xFFFF - (unsigned int)ee->d[k]); | |
384 ee->d[k] = (unsigned short)t; | |
385 t >>= 16; | |
386 } | |
387 } | |
388 } | |
389 /* contruct and normalize result */ | |
390 mpz_set_si(z, 0); | |
391 z->val = sz; | |
392 z->ptr = ez; | |
393 normalize(z); | |
394 done: return; | |
395 } | |
396 | |
397 void mpz_sub(mpz_t z, mpz_t x, mpz_t y) | |
398 { /* set z to x - y */ | |
399 if (x == y) | |
400 mpz_set_si(z, 0); | |
401 else | |
402 { y->val = - y->val; | |
403 mpz_add(z, x, y); | |
404 if (y != z) y->val = - y->val; | |
405 } | |
406 return; | |
407 } | |
408 | |
409 void mpz_mul(mpz_t z, mpz_t x, mpz_t y) | |
410 { /* set z to x * y */ | |
411 struct mpz_seg dumx, dumy, *ex, *ey, *es, *e; | |
412 int sx, sy, k, nx, ny, n; | |
413 unsigned int t; | |
414 unsigned short *work, *wx, *wy; | |
415 /* if [x] = 0 then [z] = 0 */ | |
416 if (x->val == 0) | |
417 { xassert(x->ptr == NULL); | |
418 mpz_set_si(z, 0); | |
419 goto done; | |
420 } | |
421 /* if [y] = 0 then [z] = 0 */ | |
422 if (y->val == 0) | |
423 { xassert(y->ptr == NULL); | |
424 mpz_set_si(z, 0); | |
425 goto done; | |
426 } | |
427 /* special case when both [x] and [y] are in short format */ | |
428 if (x->ptr == NULL && y->ptr == NULL) | |
429 { int xval = x->val, yval = y->val, sz = +1; | |
430 xassert(xval != 0x80000000 && yval != 0x80000000); | |
431 if (xval < 0) xval = - xval, sz = - sz; | |
432 if (yval < 0) yval = - yval, sz = - sz; | |
433 if (xval <= 0x7FFFFFFF / yval) | |
434 { mpz_set_si(z, sz * (xval * yval)); | |
435 goto done; | |
436 } | |
437 } | |
438 /* convert [x] to long format, if necessary */ | |
439 if (x->ptr == NULL) | |
440 { xassert(x->val != 0x80000000); | |
441 if (x->val >= 0) | |
442 { sx = +1; | |
443 t = (unsigned int)(+ x->val); | |
444 } | |
445 else | |
446 { sx = -1; | |
447 t = (unsigned int)(- x->val); | |
448 } | |
449 ex = &dumx; | |
450 ex->d[0] = (unsigned short)t; | |
451 ex->d[1] = (unsigned short)(t >> 16); | |
452 ex->d[2] = ex->d[3] = ex->d[4] = ex->d[5] = 0; | |
453 ex->next = NULL; | |
454 } | |
455 else | |
456 { sx = x->val; | |
457 xassert(sx == +1 || sx == -1); | |
458 ex = x->ptr; | |
459 } | |
460 /* convert [y] to long format, if necessary */ | |
461 if (y->ptr == NULL) | |
462 { xassert(y->val != 0x80000000); | |
463 if (y->val >= 0) | |
464 { sy = +1; | |
465 t = (unsigned int)(+ y->val); | |
466 } | |
467 else | |
468 { sy = -1; | |
469 t = (unsigned int)(- y->val); | |
470 } | |
471 ey = &dumy; | |
472 ey->d[0] = (unsigned short)t; | |
473 ey->d[1] = (unsigned short)(t >> 16); | |
474 ey->d[2] = ey->d[3] = ey->d[4] = ey->d[5] = 0; | |
475 ey->next = NULL; | |
476 } | |
477 else | |
478 { sy = y->val; | |
479 xassert(sy == +1 || sy == -1); | |
480 ey = y->ptr; | |
481 } | |
482 /* determine the number of digits of [x] */ | |
483 nx = n = 0; | |
484 for (e = ex; e != NULL; e = e->next) | |
485 for (k = 0; k <= 5; k++) | |
486 { n++; | |
487 if (e->d[k]) nx = n; | |
488 } | |
489 xassert(nx > 0); | |
490 /* determine the number of digits of [y] */ | |
491 ny = n = 0; | |
492 for (e = ey; e != NULL; e = e->next) | |
493 for (k = 0; k <= 5; k++) | |
494 { n++; | |
495 if (e->d[k]) ny = n; | |
496 } | |
497 xassert(ny > 0); | |
498 /* we need working array containing at least nx+ny+ny places */ | |
499 work = gmp_get_work(nx+ny+ny); | |
500 /* load digits of [x] */ | |
501 wx = &work[0]; | |
502 for (n = 0; n < nx; n++) wx[ny+n] = 0; | |
503 for (n = 0, e = ex; e != NULL; e = e->next) | |
504 for (k = 0; k <= 5; k++, n++) | |
505 if (e->d[k]) wx[ny+n] = e->d[k]; | |
506 /* load digits of [y] */ | |
507 wy = &work[nx+ny]; | |
508 for (n = 0; n < ny; n++) wy[n] = 0; | |
509 for (n = 0, e = ey; e != NULL; e = e->next) | |
510 for (k = 0; k <= 5; k++, n++) | |
511 if (e->d[k]) wy[n] = e->d[k]; | |
512 /* compute [x] * [y] */ | |
513 bigmul(nx, ny, wx, wy); | |
514 /* construct and normalize result */ | |
515 mpz_set_si(z, 0); | |
516 z->val = sx * sy; | |
517 es = NULL; | |
518 k = 6; | |
519 for (n = 0; n < nx+ny; n++) | |
520 { if (k > 5) | |
521 { e = gmp_get_atom(sizeof(struct mpz_seg)); | |
522 e->d[0] = e->d[1] = e->d[2] = 0; | |
523 e->d[3] = e->d[4] = e->d[5] = 0; | |
524 e->next = NULL; | |
525 if (z->ptr == NULL) | |
526 z->ptr = e; | |
527 else | |
528 es->next = e; | |
529 es = e; | |
530 k = 0; | |
531 } | |
532 es->d[k++] = wx[n]; | |
533 } | |
534 normalize(z); | |
535 done: return; | |
536 } | |
537 | |
538 void mpz_neg(mpz_t z, mpz_t x) | |
539 { /* set z to 0 - x */ | |
540 mpz_set(z, x); | |
541 z->val = - z->val; | |
542 return; | |
543 } | |
544 | |
545 void mpz_abs(mpz_t z, mpz_t x) | |
546 { /* set z to the absolute value of x */ | |
547 mpz_set(z, x); | |
548 if (z->val < 0) z->val = - z->val; | |
549 return; | |
550 } | |
551 | |
552 void mpz_div(mpz_t q, mpz_t r, mpz_t x, mpz_t y) | |
553 { /* divide x by y, forming quotient q and/or remainder r | |
554 if q = NULL then quotient is not stored; if r = NULL then | |
555 remainder is not stored | |
556 the sign of quotient is determined as in algebra while the | |
557 sign of remainder is the same as the sign of dividend: | |
558 +26 : +7 = +3, remainder is +5 | |
559 -26 : +7 = -3, remainder is -5 | |
560 +26 : -7 = -3, remainder is +5 | |
561 -26 : -7 = +3, remainder is -5 */ | |
562 struct mpz_seg dumx, dumy, *ex, *ey, *es, *e; | |
563 int sx, sy, k, nx, ny, n; | |
564 unsigned int t; | |
565 unsigned short *work, *wx, *wy; | |
566 /* divide by zero is not allowed */ | |
567 if (y->val == 0) | |
568 { xassert(y->ptr == NULL); | |
569 xfault("mpz_div: divide by zero not allowed\n"); | |
570 } | |
571 /* if [x] = 0 then [q] = [r] = 0 */ | |
572 if (x->val == 0) | |
573 { xassert(x->ptr == NULL); | |
574 if (q != NULL) mpz_set_si(q, 0); | |
575 if (r != NULL) mpz_set_si(r, 0); | |
576 goto done; | |
577 } | |
578 /* special case when both [x] and [y] are in short format */ | |
579 if (x->ptr == NULL && y->ptr == NULL) | |
580 { int xval = x->val, yval = y->val; | |
581 xassert(xval != 0x80000000 && yval != 0x80000000); | |
582 if (q != NULL) mpz_set_si(q, xval / yval); | |
583 if (r != NULL) mpz_set_si(r, xval % yval); | |
584 goto done; | |
585 } | |
586 /* convert [x] to long format, if necessary */ | |
587 if (x->ptr == NULL) | |
588 { xassert(x->val != 0x80000000); | |
589 if (x->val >= 0) | |
590 { sx = +1; | |
591 t = (unsigned int)(+ x->val); | |
592 } | |
593 else | |
594 { sx = -1; | |
595 t = (unsigned int)(- x->val); | |
596 } | |
597 ex = &dumx; | |
598 ex->d[0] = (unsigned short)t; | |
599 ex->d[1] = (unsigned short)(t >> 16); | |
600 ex->d[2] = ex->d[3] = ex->d[4] = ex->d[5] = 0; | |
601 ex->next = NULL; | |
602 } | |
603 else | |
604 { sx = x->val; | |
605 xassert(sx == +1 || sx == -1); | |
606 ex = x->ptr; | |
607 } | |
608 /* convert [y] to long format, if necessary */ | |
609 if (y->ptr == NULL) | |
610 { xassert(y->val != 0x80000000); | |
611 if (y->val >= 0) | |
612 { sy = +1; | |
613 t = (unsigned int)(+ y->val); | |
614 } | |
615 else | |
616 { sy = -1; | |
617 t = (unsigned int)(- y->val); | |
618 } | |
619 ey = &dumy; | |
620 ey->d[0] = (unsigned short)t; | |
621 ey->d[1] = (unsigned short)(t >> 16); | |
622 ey->d[2] = ey->d[3] = ey->d[4] = ey->d[5] = 0; | |
623 ey->next = NULL; | |
624 } | |
625 else | |
626 { sy = y->val; | |
627 xassert(sy == +1 || sy == -1); | |
628 ey = y->ptr; | |
629 } | |
630 /* determine the number of digits of [x] */ | |
631 nx = n = 0; | |
632 for (e = ex; e != NULL; e = e->next) | |
633 for (k = 0; k <= 5; k++) | |
634 { n++; | |
635 if (e->d[k]) nx = n; | |
636 } | |
637 xassert(nx > 0); | |
638 /* determine the number of digits of [y] */ | |
639 ny = n = 0; | |
640 for (e = ey; e != NULL; e = e->next) | |
641 for (k = 0; k <= 5; k++) | |
642 { n++; | |
643 if (e->d[k]) ny = n; | |
644 } | |
645 xassert(ny > 0); | |
646 /* if nx < ny then [q] = 0 and [r] = [x] */ | |
647 if (nx < ny) | |
648 { if (r != NULL) mpz_set(r, x); | |
649 if (q != NULL) mpz_set_si(q, 0); | |
650 goto done; | |
651 } | |
652 /* we need working array containing at least nx+ny+1 places */ | |
653 work = gmp_get_work(nx+ny+1); | |
654 /* load digits of [x] */ | |
655 wx = &work[0]; | |
656 for (n = 0; n < nx; n++) wx[n] = 0; | |
657 for (n = 0, e = ex; e != NULL; e = e->next) | |
658 for (k = 0; k <= 5; k++, n++) | |
659 if (e->d[k]) wx[n] = e->d[k]; | |
660 /* load digits of [y] */ | |
661 wy = &work[nx+1]; | |
662 for (n = 0; n < ny; n++) wy[n] = 0; | |
663 for (n = 0, e = ey; e != NULL; e = e->next) | |
664 for (k = 0; k <= 5; k++, n++) | |
665 if (e->d[k]) wy[n] = e->d[k]; | |
666 /* compute quotient and remainder */ | |
667 xassert(wy[ny-1] != 0); | |
668 bigdiv(nx-ny, ny, wx, wy); | |
669 /* construct and normalize quotient */ | |
670 if (q != NULL) | |
671 { mpz_set_si(q, 0); | |
672 q->val = sx * sy; | |
673 es = NULL; | |
674 k = 6; | |
675 for (n = ny; n <= nx; n++) | |
676 { if (k > 5) | |
677 { e = gmp_get_atom(sizeof(struct mpz_seg)); | |
678 e->d[0] = e->d[1] = e->d[2] = 0; | |
679 e->d[3] = e->d[4] = e->d[5] = 0; | |
680 e->next = NULL; | |
681 if (q->ptr == NULL) | |
682 q->ptr = e; | |
683 else | |
684 es->next = e; | |
685 es = e; | |
686 k = 0; | |
687 } | |
688 es->d[k++] = wx[n]; | |
689 } | |
690 normalize(q); | |
691 } | |
692 /* construct and normalize remainder */ | |
693 if (r != NULL) | |
694 { mpz_set_si(r, 0); | |
695 r->val = sx; | |
696 es = NULL; | |
697 k = 6; | |
698 for (n = 0; n < ny; n++) | |
699 { if (k > 5) | |
700 { e = gmp_get_atom(sizeof(struct mpz_seg)); | |
701 e->d[0] = e->d[1] = e->d[2] = 0; | |
702 e->d[3] = e->d[4] = e->d[5] = 0; | |
703 e->next = NULL; | |
704 if (r->ptr == NULL) | |
705 r->ptr = e; | |
706 else | |
707 es->next = e; | |
708 es = e; | |
709 k = 0; | |
710 } | |
711 es->d[k++] = wx[n]; | |
712 } | |
713 normalize(r); | |
714 } | |
715 done: return; | |
716 } | |
717 | |
718 void mpz_gcd(mpz_t z, mpz_t x, mpz_t y) | |
719 { /* set z to the greatest common divisor of x and y */ | |
720 /* in case of arbitrary integers GCD(x, y) = GCD(|x|, |y|), and, | |
721 in particular, GCD(0, 0) = 0 */ | |
722 mpz_t u, v, r; | |
723 mpz_init(u); | |
724 mpz_init(v); | |
725 mpz_init(r); | |
726 mpz_abs(u, x); | |
727 mpz_abs(v, y); | |
728 while (mpz_sgn(v)) | |
729 { mpz_div(NULL, r, u, v); | |
730 mpz_set(u, v); | |
731 mpz_set(v, r); | |
732 } | |
733 mpz_set(z, u); | |
734 mpz_clear(u); | |
735 mpz_clear(v); | |
736 mpz_clear(r); | |
737 return; | |
738 } | |
739 | |
740 int mpz_cmp(mpz_t x, mpz_t y) | |
741 { /* compare x and y; return a positive value if x > y, zero if | |
742 x = y, or a nefative value if x < y */ | |
743 static struct mpz_seg zero = { { 0, 0, 0, 0, 0, 0 }, NULL }; | |
744 struct mpz_seg dumx, dumy, *ex, *ey; | |
745 int cc, sx, sy, k; | |
746 unsigned int t; | |
747 if (x == y) | |
748 { cc = 0; | |
749 goto done; | |
750 } | |
751 /* special case when both [x] and [y] are in short format */ | |
752 if (x->ptr == NULL && y->ptr == NULL) | |
753 { int xval = x->val, yval = y->val; | |
754 xassert(xval != 0x80000000 && yval != 0x80000000); | |
755 cc = (xval > yval ? +1 : xval < yval ? -1 : 0); | |
756 goto done; | |
757 } | |
758 /* special case when [x] and [y] have different signs */ | |
759 if (x->val > 0 && y->val <= 0 || x->val == 0 && y->val < 0) | |
760 { cc = +1; | |
761 goto done; | |
762 } | |
763 if (x->val < 0 && y->val >= 0 || x->val == 0 && y->val > 0) | |
764 { cc = -1; | |
765 goto done; | |
766 } | |
767 /* convert [x] to long format, if necessary */ | |
768 if (x->ptr == NULL) | |
769 { xassert(x->val != 0x80000000); | |
770 if (x->val >= 0) | |
771 { sx = +1; | |
772 t = (unsigned int)(+ x->val); | |
773 } | |
774 else | |
775 { sx = -1; | |
776 t = (unsigned int)(- x->val); | |
777 } | |
778 ex = &dumx; | |
779 ex->d[0] = (unsigned short)t; | |
780 ex->d[1] = (unsigned short)(t >> 16); | |
781 ex->d[2] = ex->d[3] = ex->d[4] = ex->d[5] = 0; | |
782 ex->next = NULL; | |
783 } | |
784 else | |
785 { sx = x->val; | |
786 xassert(sx == +1 || sx == -1); | |
787 ex = x->ptr; | |
788 } | |
789 /* convert [y] to long format, if necessary */ | |
790 if (y->ptr == NULL) | |
791 { xassert(y->val != 0x80000000); | |
792 if (y->val >= 0) | |
793 { sy = +1; | |
794 t = (unsigned int)(+ y->val); | |
795 } | |
796 else | |
797 { sy = -1; | |
798 t = (unsigned int)(- y->val); | |
799 } | |
800 ey = &dumy; | |
801 ey->d[0] = (unsigned short)t; | |
802 ey->d[1] = (unsigned short)(t >> 16); | |
803 ey->d[2] = ey->d[3] = ey->d[4] = ey->d[5] = 0; | |
804 ey->next = NULL; | |
805 } | |
806 else | |
807 { sy = y->val; | |
808 xassert(sy == +1 || sy == -1); | |
809 ey = y->ptr; | |
810 } | |
811 /* main fragment */ | |
812 xassert(sx > 0 && sy > 0 || sx < 0 && sy < 0); | |
813 cc = 0; | |
814 for (; ex || ey; ex = ex->next, ey = ey->next) | |
815 { if (ex == NULL) ex = &zero; | |
816 if (ey == NULL) ey = &zero; | |
817 for (k = 0; k <= 5; k++) | |
818 { if (ex->d[k] > ey->d[k]) cc = +1; | |
819 if (ex->d[k] < ey->d[k]) cc = -1; | |
820 } | |
821 } | |
822 if (sx < 0) cc = - cc; | |
823 done: return cc; | |
824 } | |
825 | |
826 int mpz_sgn(mpz_t x) | |
827 { /* return +1 if x > 0, 0 if x = 0, and -1 if x < 0 */ | |
828 int s; | |
829 s = (x->val > 0 ? +1 : x->val < 0 ? -1 : 0); | |
830 return s; | |
831 } | |
832 | |
833 int mpz_out_str(void *_fp, int base, mpz_t x) | |
834 { /* output x on stream fp, as a string in given base; the base | |
835 may vary from 2 to 36; | |
836 return the number of bytes written, or if an error occurred, | |
837 return 0 */ | |
838 FILE *fp = _fp; | |
839 mpz_t b, y, r; | |
840 int n, j, nwr = 0; | |
841 unsigned char *d; | |
842 static char *set = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; | |
843 if (!(2 <= base && base <= 36)) | |
844 xfault("mpz_out_str: base = %d; invalid base\n", base); | |
845 mpz_init(b); | |
846 mpz_set_si(b, base); | |
847 mpz_init(y); | |
848 mpz_init(r); | |
849 /* determine the number of digits */ | |
850 mpz_abs(y, x); | |
851 for (n = 0; mpz_sgn(y) != 0; n++) | |
852 mpz_div(y, NULL, y, b); | |
853 if (n == 0) n = 1; | |
854 /* compute the digits */ | |
855 d = xmalloc(n); | |
856 mpz_abs(y, x); | |
857 for (j = 0; j < n; j++) | |
858 { mpz_div(y, r, y, b); | |
859 xassert(0 <= r->val && r->val < base && r->ptr == NULL); | |
860 d[j] = (unsigned char)r->val; | |
861 } | |
862 /* output the integer to the stream */ | |
863 if (fp == NULL) fp = stdout; | |
864 if (mpz_sgn(x) < 0) | |
865 fputc('-', fp), nwr++; | |
866 for (j = n-1; j >= 0; j--) | |
867 fputc(set[d[j]], fp), nwr++; | |
868 if (ferror(fp)) nwr = 0; | |
869 mpz_clear(b); | |
870 mpz_clear(y); | |
871 mpz_clear(r); | |
872 xfree(d); | |
873 return nwr; | |
874 } | |
875 | |
876 /*====================================================================*/ | |
877 | |
878 mpq_t _mpq_init(void) | |
879 { /* initialize x, and set its value to 0/1 */ | |
880 mpq_t x; | |
881 x = gmp_get_atom(sizeof(struct mpq)); | |
882 x->p.val = 0; | |
883 x->p.ptr = NULL; | |
884 x->q.val = 1; | |
885 x->q.ptr = NULL; | |
886 return x; | |
887 } | |
888 | |
889 void mpq_clear(mpq_t x) | |
890 { /* free the space occupied by x */ | |
891 mpz_set_si(&x->p, 0); | |
892 xassert(x->p.ptr == NULL); | |
893 mpz_set_si(&x->q, 0); | |
894 xassert(x->q.ptr == NULL); | |
895 /* free the number descriptor */ | |
896 gmp_free_atom(x, sizeof(struct mpq)); | |
897 return; | |
898 } | |
899 | |
900 void mpq_canonicalize(mpq_t x) | |
901 { /* remove any factors that are common to the numerator and | |
902 denominator of x, and make the denominator positive */ | |
903 mpz_t f; | |
904 xassert(x->q.val != 0); | |
905 if (x->q.val < 0) | |
906 { mpz_neg(&x->p, &x->p); | |
907 mpz_neg(&x->q, &x->q); | |
908 } | |
909 mpz_init(f); | |
910 mpz_gcd(f, &x->p, &x->q); | |
911 if (!(f->val == 1 && f->ptr == NULL)) | |
912 { mpz_div(&x->p, NULL, &x->p, f); | |
913 mpz_div(&x->q, NULL, &x->q, f); | |
914 } | |
915 mpz_clear(f); | |
916 return; | |
917 } | |
918 | |
919 void mpq_set(mpq_t z, mpq_t x) | |
920 { /* set the value of z from x */ | |
921 if (z != x) | |
922 { mpz_set(&z->p, &x->p); | |
923 mpz_set(&z->q, &x->q); | |
924 } | |
925 return; | |
926 } | |
927 | |
928 void mpq_set_si(mpq_t x, int p, unsigned int q) | |
929 { /* set the value of x to p/q */ | |
930 if (q == 0) | |
931 xfault("mpq_set_si: zero denominator not allowed\n"); | |
932 mpz_set_si(&x->p, p); | |
933 xassert(q <= 0x7FFFFFFF); | |
934 mpz_set_si(&x->q, q); | |
935 return; | |
936 } | |
937 | |
938 double mpq_get_d(mpq_t x) | |
939 { /* convert x to a double, truncating if necessary */ | |
940 int np, nq; | |
941 double p, q; | |
942 p = mpz_get_d_2exp(&np, &x->p); | |
943 q = mpz_get_d_2exp(&nq, &x->q); | |
944 return ldexp(p / q, np - nq); | |
945 } | |
946 | |
947 void mpq_set_d(mpq_t x, double val) | |
948 { /* set x to val; there is no rounding, the conversion is exact */ | |
949 int s, n, d, j; | |
950 double f; | |
951 mpz_t temp; | |
952 xassert(-DBL_MAX <= val && val <= +DBL_MAX); | |
953 mpq_set_si(x, 0, 1); | |
954 if (val > 0.0) | |
955 s = +1; | |
956 else if (val < 0.0) | |
957 s = -1; | |
958 else | |
959 goto done; | |
960 f = frexp(fabs(val), &n); | |
961 /* |val| = f * 2^n, where 0.5 <= f < 1.0 */ | |
962 mpz_init(temp); | |
963 while (f != 0.0) | |
964 { f *= 16.0, n -= 4; | |
965 d = (int)f; | |
966 xassert(0 <= d && d <= 15); | |
967 f -= (double)d; | |
968 /* x := 16 * x + d */ | |
969 mpz_set_si(temp, 16); | |
970 mpz_mul(&x->p, &x->p, temp); | |
971 mpz_set_si(temp, d); | |
972 mpz_add(&x->p, &x->p, temp); | |
973 } | |
974 mpz_clear(temp); | |
975 /* x := x * 2^n */ | |
976 if (n > 0) | |
977 { for (j = 1; j <= n; j++) | |
978 mpz_add(&x->p, &x->p, &x->p); | |
979 } | |
980 else if (n < 0) | |
981 { for (j = 1; j <= -n; j++) | |
982 mpz_add(&x->q, &x->q, &x->q); | |
983 mpq_canonicalize(x); | |
984 } | |
985 if (s < 0) mpq_neg(x, x); | |
986 done: return; | |
987 } | |
988 | |
989 void mpq_add(mpq_t z, mpq_t x, mpq_t y) | |
990 { /* set z to x + y */ | |
991 mpz_t p, q; | |
992 mpz_init(p); | |
993 mpz_init(q); | |
994 mpz_mul(p, &x->p, &y->q); | |
995 mpz_mul(q, &x->q, &y->p); | |
996 mpz_add(p, p, q); | |
997 mpz_mul(q, &x->q, &y->q); | |
998 mpz_set(&z->p, p); | |
999 mpz_set(&z->q, q); | |
1000 mpz_clear(p); | |
1001 mpz_clear(q); | |
1002 mpq_canonicalize(z); | |
1003 return; | |
1004 } | |
1005 | |
1006 void mpq_sub(mpq_t z, mpq_t x, mpq_t y) | |
1007 { /* set z to x - y */ | |
1008 mpz_t p, q; | |
1009 mpz_init(p); | |
1010 mpz_init(q); | |
1011 mpz_mul(p, &x->p, &y->q); | |
1012 mpz_mul(q, &x->q, &y->p); | |
1013 mpz_sub(p, p, q); | |
1014 mpz_mul(q, &x->q, &y->q); | |
1015 mpz_set(&z->p, p); | |
1016 mpz_set(&z->q, q); | |
1017 mpz_clear(p); | |
1018 mpz_clear(q); | |
1019 mpq_canonicalize(z); | |
1020 return; | |
1021 } | |
1022 | |
1023 void mpq_mul(mpq_t z, mpq_t x, mpq_t y) | |
1024 { /* set z to x * y */ | |
1025 mpz_mul(&z->p, &x->p, &y->p); | |
1026 mpz_mul(&z->q, &x->q, &y->q); | |
1027 mpq_canonicalize(z); | |
1028 return; | |
1029 } | |
1030 | |
1031 void mpq_div(mpq_t z, mpq_t x, mpq_t y) | |
1032 { /* set z to x / y */ | |
1033 mpz_t p, q; | |
1034 if (mpq_sgn(y) == 0) | |
1035 xfault("mpq_div: zero divisor not allowed\n"); | |
1036 mpz_init(p); | |
1037 mpz_init(q); | |
1038 mpz_mul(p, &x->p, &y->q); | |
1039 mpz_mul(q, &x->q, &y->p); | |
1040 mpz_set(&z->p, p); | |
1041 mpz_set(&z->q, q); | |
1042 mpz_clear(p); | |
1043 mpz_clear(q); | |
1044 mpq_canonicalize(z); | |
1045 return; | |
1046 } | |
1047 | |
1048 void mpq_neg(mpq_t z, mpq_t x) | |
1049 { /* set z to 0 - x */ | |
1050 mpq_set(z, x); | |
1051 mpz_neg(&z->p, &z->p); | |
1052 return; | |
1053 } | |
1054 | |
1055 void mpq_abs(mpq_t z, mpq_t x) | |
1056 { /* set z to the absolute value of x */ | |
1057 mpq_set(z, x); | |
1058 mpz_abs(&z->p, &z->p); | |
1059 xassert(mpz_sgn(&x->q) > 0); | |
1060 return; | |
1061 } | |
1062 | |
1063 int mpq_cmp(mpq_t x, mpq_t y) | |
1064 { /* compare x and y; return a positive value if x > y, zero if | |
1065 x = y, or a nefative value if x < y */ | |
1066 mpq_t temp; | |
1067 int s; | |
1068 mpq_init(temp); | |
1069 mpq_sub(temp, x, y); | |
1070 s = mpq_sgn(temp); | |
1071 mpq_clear(temp); | |
1072 return s; | |
1073 } | |
1074 | |
1075 int mpq_sgn(mpq_t x) | |
1076 { /* return +1 if x > 0, 0 if x = 0, and -1 if x < 0 */ | |
1077 int s; | |
1078 s = mpz_sgn(&x->p); | |
1079 xassert(mpz_sgn(&x->q) > 0); | |
1080 return s; | |
1081 } | |
1082 | |
1083 int mpq_out_str(void *_fp, int base, mpq_t x) | |
1084 { /* output x on stream fp, as a string in given base; the base | |
1085 may vary from 2 to 36; output is in the form 'num/den' or if | |
1086 the denominator is 1 then just 'num'; | |
1087 if the parameter fp is a null pointer, stdout is assumed; | |
1088 return the number of bytes written, or if an error occurred, | |
1089 return 0 */ | |
1090 FILE *fp = _fp; | |
1091 int nwr; | |
1092 if (!(2 <= base && base <= 36)) | |
1093 xfault("mpq_out_str: base = %d; invalid base\n", base); | |
1094 if (fp == NULL) fp = stdout; | |
1095 nwr = mpz_out_str(fp, base, &x->p); | |
1096 if (x->q.val == 1 && x->q.ptr == NULL) | |
1097 ; | |
1098 else | |
1099 { fputc('/', fp), nwr++; | |
1100 nwr += mpz_out_str(fp, base, &x->q); | |
1101 } | |
1102 if (ferror(fp)) nwr = 0; | |
1103 return nwr; | |
1104 } | |
1105 | |
1106 #endif | |
1107 | |
1108 /* eof */ |