blob: d393be3b86d137e7095aac84b91dc73dfc998343 [file] [log] [blame]
Guido van Rossum5f59d601992-12-14 16:59:51 +00001/***********************************************************
Guido van Rossum524b5881995-01-04 19:10:35 +00002Copyright 1991-1995 by Stichting Mathematisch Centrum, Amsterdam,
3The Netherlands.
Guido van Rossum5f59d601992-12-14 16:59:51 +00004
5 All Rights Reserved
6
7Permission to use, copy, modify, and distribute this software and its
8documentation for any purpose and without fee is hereby granted,
9provided that the above copyright notice appear in all copies and that
10both that copyright notice and this permission notice appear in
11supporting documentation, and that the names of Stichting Mathematisch
12Centrum or CWI not be used in advertising or publicity pertaining to
13distribution of the software without specific, written prior permission.
14
15STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
16THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
18FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
21OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22
23******************************************************************/
Guido van Rossumb6775db1994-08-01 11:34:53 +000024
Guido van Rossum5f59d601992-12-14 16:59:51 +000025/* MPZ module */
26
27/* This module provides an interface to an alternate Multi-Precision
28 library, GNU MP in this case */
29
30/* XXX note: everywhere where mpz_size is called,
31 sizeof (limb) == sizeof (long) has been assumed. */
32
33
34/* MPZ objects */
35
36#include "allobjects.h"
Guido van Rossuma597dde1995-01-10 20:56:29 +000037
Guido van Rossum5f59d601992-12-14 16:59:51 +000038#include <assert.h>
Guido van Rossumb6775db1994-08-01 11:34:53 +000039#include <sys/types.h> /* For size_t */
Guido van Rossum5f59d601992-12-14 16:59:51 +000040
41/*
42** These are the cpp-flags used in this file...
43**
44**
45** MPZ_MDIV_BUG works around the mpz_m{div,mod,...} routines.
46** This bug has been fixed in a later release of
47** GMP.
48**
49** MPZ_GET_STR_BUG mpz_get_str corrupts memory, seems to be fixed
50** in a later release
51**
52** MPZ_DEBUG generates a bunch of diagnostic messages
53**
54** MPZ_SPARE_MALLOC if set, results in extra code that tries to
55** minimize the creation of extra objects.
56**
57** MPZ_TEST_DIV extra diagnostic output on stderr, when division
58** routines are involved
59**
60** MPZ_LIB_DOES_CHECKING if set, assumes that mpz library doesn't call
61** alloca with arg < 0 (when casted to a signed
62** integral type).
63**
64** MPZ_CONVERSIONS_AS_METHODS if set, presents the conversions as
65** methods. e.g., `mpz(5).long() == 5L'
66** Later, Guido provided an interface to the
67** standard functions. So this flag has no been
68** cleared, and `long(mpz(5)) == 5L'
69**
70** MP_TEST_ALLOC If set, you would discover why MPZ_GET_STR_BUG
71** is needed
72**
73** MAKEDUMMYINT Must be set if dynamic linking will be used
74*/
75
76
77/*
78** IMHO, mpz_m{div,mod,divmod}() do the wrong things when the denominator < 0
Guido van Rossum272841c1996-08-19 23:06:45 +000079** This has been fixed with gmp release 2.0
Guido van Rossum5f59d601992-12-14 16:59:51 +000080*/
81/*#define MPZ_MDIV_BUG fixed the (for me) nexessary parts in libgmp.a */
82/*
83** IMO, mpz_get_str() assumes a bit too large target space, if he doesn't
84** allocate it himself
85*/
Guido van Rossum5f59d601992-12-14 16:59:51 +000086
87#include "gmp.h"
Guido van Rossum272841c1996-08-19 23:06:45 +000088#include "gmp-impl.h"
89
90#if __GNU_MP__ == 2
91#define GMP2
92#else
93#define MPZ_GET_STR_BUG
94#endif
95
Guido van Rossum5f59d601992-12-14 16:59:51 +000096typedef struct {
97 OB_HEAD
98 MP_INT mpz; /* the actual number */
99} mpzobject;
100
Guido van Rossumb6775db1994-08-01 11:34:53 +0000101staticforward typeobject MPZtype;
Guido van Rossum5f59d601992-12-14 16:59:51 +0000102
103#define is_mpzobject(v) ((v)->ob_type == &MPZtype)
104
105static const char initialiser_name[] = "mpz";
106
107/* #define MPZ_DEBUG */
108
109static mpzobject *
110newmpzobject()
111{
112 mpzobject *mpzp;
113
114
115#ifdef MPZ_DEBUG
116 fputs( "mpz_object() called...\n", stderr );
117#endif /* def MPZ_DEBUG */
118 mpzp = NEWOBJ(mpzobject, &MPZtype);
119 if (mpzp == NULL)
120 return NULL;
121
122 mpz_init(&mpzp->mpz); /* actual initialisation */
123 return mpzp;
124} /* newmpzobject() */
125
126#ifdef MPZ_GET_STR_BUG
Guido van Rossum5f59d601992-12-14 16:59:51 +0000127#include "longlong.h"
128#endif /* def MPZ_GET_STR_BUG */
129
130static object *
131mpz_format(objp, base, withname)
132 object *objp;
133 int base;
134 unsigned char withname;
135{
136 mpzobject *mpzp = (mpzobject *)objp;
137 stringobject *strobjp;
138 int i;
139 int cmpres;
140 int taglong;
141 char *cp;
142 char prefix[5], *tcp;
143
144
145 tcp = &prefix[0];
146
147 if (mpzp == NULL || !is_mpzobject(mpzp)) {
148 err_badcall();
149 return NULL;
150 }
151
152 assert(base >= 2 && base <= 36);
153
154 if (withname)
155 i = strlen(initialiser_name) + 2; /* e.g. 'mpz(' + ')' */
156 else
157 i = 0;
158
159 if ((cmpres = mpz_cmp_si(&mpzp->mpz, 0L)) == 0)
160 base = 10; /* '0' in every base, right */
161 else if (cmpres < 0) {
162 *tcp++ = '-';
163 i += 1; /* space to hold '-' */
164 }
165
166#ifdef MPZ_DEBUG
167 fprintf(stderr, "mpz_format: mpz_sizeinbase %d\n",
168 (int)mpz_sizeinbase(&mpzp->mpz, base));
169#endif /* def MPZ_DEBUG */
170#ifdef MPZ_GET_STR_BUG
Guido van Rossum272841c1996-08-19 23:06:45 +0000171#ifdef GMP2
172 i += ((size_t) abs(mpzp->mpz._mp_size) * BITS_PER_MP_LIMB
173 * __mp_bases[base].chars_per_bit_exactly) + 1;
174#else
Guido van Rossum5f59d601992-12-14 16:59:51 +0000175 i += ((size_t) abs(mpzp->mpz.size) * BITS_PER_MP_LIMB
176 * __mp_bases[base].chars_per_bit_exactly) + 1;
Guido van Rossum272841c1996-08-19 23:06:45 +0000177#endif
Guido van Rossum5f59d601992-12-14 16:59:51 +0000178#else /* def MPZ_GET_STR_BUG */
179 i += (int)mpz_sizeinbase(&mpzp->mpz, base);
180#endif /* def MPZ_GET_STR_BUG else */
181
182 if (base == 16) {
183 *tcp++ = '0';
184 *tcp++ = 'x';
185 i += 2; /* space to hold '0x' */
186 }
187 else if (base == 8) {
188 *tcp++ = '0';
189 i += 1; /* space to hold the extra '0' */
190 }
191 else if (base > 10) {
192 *tcp++ = '0' + base / 10;
193 *tcp++ = '0' + base % 10;
194 *tcp++ = '#';
195 i += 3; /* space to hold e.g. '12#' */
196 }
197 else if (base < 10) {
198 *tcp++ = '0' + base;
199 *tcp++ = '#';
200 i += 2; /* space to hold e.g. '6#' */
201 }
202
203 /*
204 ** the following code looks if we need a 'L' attached to the number
205 ** it will also attach an 'L' to the value -0x80000000
206 */
207 taglong = 0;
208 if (mpz_size(&mpzp->mpz) > 1
209 || (long)mpz_get_ui(&mpzp->mpz) < 0L) {
210 taglong = 1;
211 i += 1; /* space to hold 'L' */
212 }
213
214#ifdef MPZ_DEBUG
215 fprintf(stderr, "mpz_format: requesting string size %d\n", i);
216#endif /* def MPZ_DEBUG */
217 if ((strobjp = (stringobject *)newsizedstringobject((char *)0, i))
218 == NULL)
219 return NULL;
220
221 /* get the beginning of the string memory and start copying things */
222 cp = GETSTRINGVALUE(strobjp);
223 if (withname) {
224 strcpy(cp, initialiser_name);
225 cp += strlen(initialiser_name);
226 *cp++ = '('; /*')'*/
227 }
228
229 /* copy the already prepared prefix; e.g. sign and base indicator */
230 *tcp = '\0';
231 strcpy(cp, prefix);
232 cp += tcp - prefix;
233
234 /* since' we have the sign already, let the lib think it's a positive
235 number */
236 if (cmpres < 0)
237 mpz_neg(&mpzp->mpz,&mpzp->mpz); /* hack Hack HAck HACk HACK */
238 (void)mpz_get_str(cp, base, &mpzp->mpz);
239 if (cmpres < 0)
240 mpz_neg(&mpzp->mpz,&mpzp->mpz); /* hack Hack HAck HACk HACK */
241#ifdef MPZ_DEBUG
242 fprintf(stderr, "mpz_format: base (ultim) %d, mpz_get_str: %s\n",
243 base, cp);
244#endif /* def MPZ_DEBUG */
245 cp += strlen(cp);
246
247 if (taglong)
248 *cp++ = 'L';
249 if (withname)
250 *cp++ = /*'('*/ ')';
251
252 *cp = '\0';
253
254#ifdef MPZ_DEBUG
255 fprintf(stderr,
256 "mpz_format: cp (str end) 0x%x, begin 0x%x, diff %d, i %d\n",
257 cp, GETSTRINGVALUE(strobjp), cp - GETSTRINGVALUE(strobjp), i);
258#endif /* def MPZ_DEBUG */
259 assert(cp - GETSTRINGVALUE(strobjp) <= i);
260
261 if (cp - GETSTRINGVALUE(strobjp) != i) {
262 strobjp->ob_size -= i - (cp - GETSTRINGVALUE(strobjp));
263 }
264
265 return (object *)strobjp;
266} /* mpz_format() */
267
268/* MPZ methods */
269
270static void
271mpz_dealloc(mpzp)
272 mpzobject *mpzp;
273{
274#ifdef MPZ_DEBUG
275 fputs( "mpz_dealloc() called...\n", stderr );
276#endif /* def MPZ_DEBUG */
277 mpz_clear(&mpzp->mpz);
278 DEL(mpzp);
279} /* mpz_dealloc() */
280
Guido van Rossum5f59d601992-12-14 16:59:51 +0000281
282/* pointers to frequently used values 0, 1 and -1 */
283static mpzobject *mpz_value_zero, *mpz_value_one, *mpz_value_mone;
284
285static int
286mpz_compare(a, b)
287 mpzobject *a, *b;
288{
289 int cmpres;
290
291
292 /* guido sez it's better to return -1, 0 or 1 */
293 return (cmpres = mpz_cmp( &a->mpz, &b->mpz )) == 0 ? 0
294 : cmpres > 0 ? 1 : -1;
295} /* mpz_compare() */
296
297static object *
298mpz_addition(a, b)
299 mpzobject *a;
300 mpzobject *b;
301{
302 mpzobject *z;
303
304
305#ifdef MPZ_SPARE_MALLOC
306 if (mpz_cmp_ui(&a->mpz, (unsigned long int)0) == 0) {
307 INCREF(b);
308 return (object *)b;
309 }
310
311 if (mpz_cmp_ui(&b->mpz, (unsigned long int)0) == 0) {
312 INCREF(a);
313 return (object *)a;
314 }
315#endif /* def MPZ_SPARE_MALLOC */
316
317 if ((z = newmpzobject()) == NULL)
318 return NULL;
319
320 mpz_add(&z->mpz, &a->mpz, &b->mpz);
321 return (object *)z;
322} /* mpz_addition() */
323
324static object *
325mpz_substract(a, b)
326 mpzobject *a;
327 mpzobject *b;
328{
329 mpzobject *z;
330
331
332#ifdef MPZ_SPARE_MALLOC
333 if (mpz_cmp_ui(&b->mpz, (unsigned long int)0) == 0) {
334 INCREF(a);
335 return (object *)a;
336 }
337#endif /* MPZ_SPARE_MALLOC */
338
339 if ((z = newmpzobject()) == NULL)
340 return NULL;
341
342 mpz_sub(&z->mpz, &a->mpz, &b->mpz);
343 return (object *)z;
344} /* mpz_substract() */
345
346static object *
347mpz_multiply(a, b)
348 mpzobject *a;
349 mpzobject *b;
350{
351#ifdef MPZ_SPARE_MALLOC
352 int cmpres;
353#endif /* def MPZ_SPARE_MALLOC */
354 mpzobject *z;
355
356
357#ifdef MPZ_SPARE_MALLOC
358 if ((cmpres = mpz_cmp_ui(&a->mpz, (unsigned long int)0)) == 0) {
359 INCREF(mpz_value_zero);
360 return (object *)mpz_value_zero;
361 }
362 if (cmpres > 0 && mpz_cmp_ui(&a->mpz, (unsigned long int)1) == 0) {
363 INCREF(b);
364 return (object *)b;
365 }
366
367 if ((cmpres = mpz_cmp_ui(&b->mpz, (unsigned long_int)0)) == 0) {
368 INCREF(mpz_value_zero);
369 return (object *)mpz_value_zero;
370 }
371 if (cmpres > 0 && mpz_cmp_ui(&b->mpz, (unsigned long int)1) == 0) {
372 INCREF(a);
373 return (object *)a;
374 }
375#endif /* MPZ_SPARE_MALLOC */
376
377 if ((z = newmpzobject()) == NULL)
378 return NULL;
379
380 mpz_mul( &z->mpz, &a->mpz, &b->mpz );
381 return (object *)z;
382
383} /* mpz_multiply() */
384
385static object *
386mpz_divide(a, b)
387 mpzobject *a;
388 mpzobject *b;
389{
390#ifdef MPZ_SPARE_MALLOC
391 int cmpres;
392#endif /* def MPZ_SPARE_MALLOC */
393 mpzobject *z;
394
395
396 if ((
397#ifdef MPZ_SPARE_MALLOC
398 cmpres =
399#endif /* def MPZ_SPARE_MALLOC */
400 mpz_cmp_ui(&b->mpz, (unsigned long int)0)) == 0) {
401 err_setstr(ZeroDivisionError, "mpz./ by zero");
402 return NULL;
403 }
404#ifdef MPZ_SPARE_MALLOC
405 if (cmpres > 0 && mpz_cmp_ui(&b->mpz(unsigned long int)1) == 0) {
406 INCREF(a);
407 return (object *)a;
408 }
409#endif /* def MPZ_SPARE_MALLOC */
410
411 if ((z = newmpzobject()) == NULL)
412 return NULL;
413
414#ifdef MPZ_TEST_DIV
415 fputs("mpz_divide: div result", stderr);
416 mpz_div(&z->mpz, &a->mpz, &b->mpz);
417 mpz_out_str(stderr, 10, &z->mpz);
418 putc('\n', stderr);
419#endif /* def MPZ_TEST_DIV */
420#ifdef MPZ_MDIV_BUG
421 if ((mpz_cmp_ui(&a->mpz, (unsigned long int)0) < 0)
422 != (mpz_cmp_ui(&b->mpz, (unsigned long int)0) < 0)) {
423 /*
424 ** numerator has other sign than denominator: we have
425 ** to look at the remainder for a correction, since mpz_mdiv
426 ** also calls mpz_divmod, I can as well do it myself
427 */
428 MP_INT tmpmpz;
429
430
431 mpz_init(&tmpmpz);
432 mpz_divmod(&z->mpz, &tmpmpz, &a->mpz, &b->mpz);
433
434 if (mpz_cmp_ui(&tmpmpz, (unsigned long int)0) != 0)
435 mpz_sub_ui(&z->mpz, &z->mpz, (unsigned long int)1);
436
437 mpz_clear(&tmpmpz);
438 }
439 else
440 mpz_div(&z->mpz, &a->mpz, &b->mpz);
441 /* the ``naive'' implementation does it right for operands
442 having the same sign */
443
444#else /* def MPZ_MDIV_BUG */
445 mpz_mdiv(&z->mpz, &a->mpz, &b->mpz);
446#endif /* def MPZ_MDIV_BUG else */
447#ifdef MPZ_TEST_DIV
448 fputs("mpz_divide: mdiv result", stderr);
449 mpz_out_str(stderr, 10, &z->mpz);
450 putc('\n', stderr);
451#endif /* def MPZ_TEST_DIV */
452 return (object *)z;
453
454} /* mpz_divide() */
455
456static object *
457mpz_remainder(a, b)
458 mpzobject *a;
459 mpzobject *b;
460{
461#ifdef MPZ_SPARE_MALLOC
462 int cmpres;
463#endif /* def MPZ_SPARE_MALLOC */
464 mpzobject *z;
465
466
467 if ((
468#ifdef MPZ_SPARE_MALLOC
469 cmpres =
470#endif /* def MPZ_SPARE_MALLOC */
471 mpz_cmp_ui(&b->mpz, (unsigned long int)0)) == 0) {
472 err_setstr(ZeroDivisionError, "mpz.% by zero");
473 return NULL;
474 }
475#ifdef MPZ_SPARE_MALLOC
476 if (cmpres > 0) {
477 if ((cmpres = mpz_cmp_ui(&b->mpz, (unsigned long int)2)) == 0) {
478 INCREF(mpz_value_one);
479 return (object *)mpz_value_one;
480 }
481 if (cmpres < 0) {
482 /* b must be 1 now */
483 INCREF(mpz_value_zero);
484 return (object *)mpz_value_zero;
485 }
486 }
487#endif /* def MPZ_SPARE_MALLOC */
488
489 if ((z = newmpzobject()) == NULL)
490 return NULL;
491
492#ifdef MPZ_TEST_DIV
493 fputs("mpz_remain: mod result", stderr);
494 mpz_mod(&z->mpz, &a->mpz, &b->mpz);
495 mpz_out_str(stderr, 10, &z->mpz);
496 putc('\n', stderr);
497#endif /* def MPZ_TEST_DIV */
498#ifdef MPZ_MDIV_BUG
499
500 /* the ``naive'' implementation does it right for operands
501 having the same sign */
502 mpz_mod(&z->mpz, &a->mpz, &b->mpz);
503
504 /* assumption: z, a and b all point to different locations */
505 if ((mpz_cmp_ui(&a->mpz, (unsigned long int)0) < 0)
506 != (mpz_cmp_ui(&b->mpz, (unsigned long int)0) < 0)
507 && mpz_cmp_ui(&z->mpz, (unsigned long int)0) != 0)
508 mpz_add(&z->mpz, &z->mpz, &b->mpz);
509 /*
510 ** numerator has other sign than denominator: we have
511 ** to look at the remainder for a correction, since mpz_mdiv
512 ** also calls mpz_divmod, I can as well do it myself
513 */
514#else /* def MPZ_MDIV_BUG */
515 mpz_mmod(&z->mpz, &a->mpz, &b->mpz);
516#endif /* def MPZ_MDIV_BUG else */
517#ifdef MPZ_TEST_DIV
518 fputs("mpz_remain: mmod result", stderr);
519 mpz_out_str(stderr, 10, &z->mpz);
520 putc('\n', stderr);
521#endif /* def MPZ_TEST_DIV */
522 return (object *)z;
523
524} /* mpz_remainder() */
525
526static object *
527mpz_div_and_mod(a, b)
528 mpzobject *a;
529 mpzobject *b;
530{
531 object *z = NULL;
532 mpzobject *x = NULL, *y = NULL;
533
534
535 if (mpz_cmp_ui(&b->mpz, (unsigned long int)0) == 0) {
536 err_setstr(ZeroDivisionError, "mpz.divmod by zero");
537 return NULL;
538 }
539
540 if ((z = newtupleobject(2)) == NULL
541 || (x = newmpzobject()) == NULL
542 || (y = newmpzobject()) == NULL) {
543 XDECREF(z);
544 XDECREF(x);
545 XDECREF(y);
546 return NULL;
547 }
548
549#ifdef MPZ_TEST_DIV
550 fputs("mpz_divmod: dm result", stderr);
551 mpz_divmod(&x->mpz, &y->mpz, &a->mpz, &b->mpz);
552 mpz_out_str(stderr, 10, &x->mpz);
553 putc('\n', stderr);
554 mpz_out_str(stderr, 10, &y->mpz);
555 putc('\n', stderr);
556#endif /* def MPZ_TEST_DIV */
557#ifdef MPZ_MDIV_BUG
558 mpz_divmod(&x->mpz, &y->mpz, &a->mpz, &b->mpz);
559 if ((mpz_cmp_ui(&a->mpz, (unsigned long int)0) < 0)
560 != (mpz_cmp_ui(&b->mpz, (unsigned long int)0) < 0)
561 && mpz_cmp_ui(&y->mpz, (unsigned long int)0) != 0) {
562 /*
563 ** numerator has other sign than denominator: we have
564 ** to look at the remainder for a correction.
565 */
566 mpz_add(&y->mpz, &y->mpz, &b->mpz);
567 mpz_sub_ui(&x->mpz, &x->mpz, (unsigned long int)1);
568 }
569#else /* def MPZ_MDIV_BUG */
570 mpz_mdivmod( &x->mpz, &y->mpz, &a->mpz, &b->mpz );
571#endif /* def MPZ_MDIV_BUG else */
572#ifdef MPZ_TEST_DIV
573 fputs("mpz_divmod: mdm result", stderr);
574 mpz_out_str(stderr, 10, &x->mpz);
575 putc('\n', stderr);
576 mpz_out_str(stderr, 10, &y->mpz);
577 putc('\n', stderr);
578#endif /* def MPZ_TEST_DIV */
579
580 (void)settupleitem(z, 0, (object *)x);
581 (void)settupleitem(z, 1, (object *)y);
582
583 return z;
584} /* mpz_div_and_mod() */
585
586static object *
Guido van Rossum3bbc62e1995-01-02 19:30:30 +0000587mpz_power(a, b, m)
Guido van Rossum5f59d601992-12-14 16:59:51 +0000588 mpzobject *a;
589 mpzobject *b;
Guido van Rossum3bbc62e1995-01-02 19:30:30 +0000590 mpzobject *m;
Guido van Rossum5f59d601992-12-14 16:59:51 +0000591{
592 mpzobject *z;
593 int cmpres;
Guido van Rossum5f59d601992-12-14 16:59:51 +0000594
Guido van Rossum3bbc62e1995-01-02 19:30:30 +0000595 if ((object *)m!=Py_None)
596 {
597 mpzobject *z2;
598 INCREF(Py_None);
Guido van Rossum760dd101995-02-10 17:01:08 +0000599 z=(mpzobject *)mpz_power(a, b, (mpzobject *)Py_None);
Guido van Rossum3bbc62e1995-01-02 19:30:30 +0000600 DECREF(Py_None);
Guido van Rossum760dd101995-02-10 17:01:08 +0000601 if (z==NULL) return((object *)z);
602 z2=(mpzobject *)mpz_remainder(z, m);
Guido van Rossum3bbc62e1995-01-02 19:30:30 +0000603 DECREF(z);
604 return((object *)z2);
605 }
Guido van Rossum5f59d601992-12-14 16:59:51 +0000606
607 if ((cmpres = mpz_cmp_ui(&b->mpz, (unsigned long int)0)) == 0) {
608 /* the gnu-mp lib sets pow(0,0) to 0, we to 1 */
609
610 INCREF(mpz_value_one);
611 return (object *)mpz_value_one;
612 }
613
614 if (cmpres < 0) {
615 err_setstr(ValueError, "mpz.pow to negative exponent");
616 return NULL;
617 }
618
619 if ((cmpres = mpz_cmp_ui(&a->mpz, (unsigned long int)0)) == 0) {
620 /* the base is 0 */
621
622 INCREF(mpz_value_zero);
623 return (object *)mpz_value_zero;
624 }
625 else if (cmpres > 0
626 && mpz_cmp_ui(&a->mpz, (unsigned long int)1) == 0) {
627 /* the base is 1 */
628
629 INCREF(mpz_value_one);
630 return (object *)mpz_value_one;
631 }
632 else if (cmpres < 0
633 && mpz_cmp_si(&a->mpz, (long int)-1) == 0) {
634
635 MP_INT tmpmpz;
636 /* the base is -1: pow(-1, any) == 1,-1 for even,uneven b */
637 /* XXX this code needs to be optimized: what's better?
638 mpz_mmod_ui or mpz_mod_2exp, I choose for the latter
639 for *un*obvious reasons */
640
641 /* is the exponent even? */
642 mpz_init(&tmpmpz);
643
644 /* look to the remainder after a division by (1 << 1) */
645 mpz_mod_2exp(&tmpmpz, &b->mpz, (unsigned long int)1);
646
647 if (mpz_cmp_ui(&tmpmpz, (unsigned int)0) == 0) {
648 mpz_clear(&tmpmpz);
649 INCREF(mpz_value_one);
650 return (object *)mpz_value_one;
651 }
652 mpz_clear(&tmpmpz);
653 INCREF(mpz_value_mone);
654 return (object *)mpz_value_mone;
655 }
656
657#ifdef MPZ_LIB_DOES_CHECKING
658 /* check if it's doable: sizeof(exp) > sizeof(long) &&
659 abs(base) > 1 ?? --> No Way */
660 if (mpz_size(&b->mpz) > 1)
661 return (object *)err_nomem();
662#else /* def MPZ_LIB_DOES_CHECKING */
663 /* wet finger method */
664 if (mpz_cmp_ui(&b->mpz, (unsigned long int)0x10000) >= 0) {
665 err_setstr(ValueError, "mpz.pow outrageous exponent");
666 return NULL;
667 }
668#endif /* def MPZ_LIB_DOES_CHECKING else */
669
670 if ((z = newmpzobject()) == NULL)
671 return NULL;
672
673 mpz_pow_ui(&z->mpz, &a->mpz, mpz_get_ui(&b->mpz));
674
675 return (object *)z;
676} /* mpz_power() */
677
678
679static object *
680mpz_negative(v)
681 mpzobject *v;
682{
683 mpzobject *z;
684
685
686#ifdef MPZ_SPARE_MALLOC
687 if (mpz_cmp_ui(&v->mpz, (unsigned long int)0) == 0) {
688 /* -0 == 0 */
689 INCREF(v);
690 return (object *)v;
691 }
692#endif /* def MPZ_SPARE_MALLOC */
693
694 if ((z = newmpzobject()) == NULL)
695 return NULL;
696
697 mpz_neg(&z->mpz, &v->mpz);
698 return (object *)z;
699} /* mpz_negative() */
700
701
702static object *
703mpz_positive(v)
704 mpzobject *v;
705{
706 INCREF(v);
707 return (object *)v;
708} /* mpz_positive() */
709
710
711static object *
712mpz_absolute(v)
713 mpzobject *v;
714{
715 mpzobject *z;
716
717
718 if (mpz_cmp_ui(&v->mpz, (unsigned long int)0) >= 0) {
719 INCREF(v);
720 return (object *)v;
721 }
722
723 if ((z = newmpzobject()) == NULL)
724 return NULL;
725
726 mpz_neg(&z->mpz, &v->mpz);
727 return (object *)z;
728} /* mpz_absolute() */
729
730static int
731mpz_nonzero(v)
732 mpzobject *v;
733{
734 return mpz_cmp_ui(&v->mpz, (unsigned long int)0) != 0;
735} /* mpz_nonzero() */
736
737static object *
Guido van Rossum272841c1996-08-19 23:06:45 +0000738py_mpz_invert(v)
Guido van Rossum5f59d601992-12-14 16:59:51 +0000739 mpzobject *v;
740{
741 mpzobject *z;
742
743
744 /* I think mpz_com does exactly what needed */
745 if ((z = newmpzobject()) == NULL)
746 return NULL;
747
748 mpz_com(&z->mpz, &v->mpz);
749 return (object *)z;
Guido van Rossum272841c1996-08-19 23:06:45 +0000750} /* py_mpz_invert() */
Guido van Rossum5f59d601992-12-14 16:59:51 +0000751
752static object *
753mpz_lshift(a, b)
754 mpzobject *a;
755 mpzobject *b;
756{
757 int cmpres;
758 mpzobject *z;
759
760
761 if ((cmpres = mpz_cmp_ui(&b->mpz, (unsigned long int)0)) == 0) {
762 /* a << 0 == a */
763 INCREF(a);
764 return (object *)a;
765 }
766
767 if (cmpres < 0) {
768 err_setstr(ValueError, "mpz.<< negative shift count");
769 return NULL;
770 }
771
772#ifdef MPZ_LIB_DOES_CHECKING
773 if (mpz_size(&b->mpz) > 1)
774 return (object *)err_nomem();
775#else /* def MPZ_LIB_DOES_CHECKING */
776 /* wet finger method */
777 if (mpz_cmp_ui(&b->mpz, (unsigned long int)0x10000) >= 0) {
778 err_setstr(ValueError, "mpz.<< outrageous shift count");
779 return NULL;
780 }
781#endif /* def MPZ_LIB_DOES_CHECKING else */
782
783 if ((z = newmpzobject()) == NULL)
784 return NULL;
785
786 mpz_mul_2exp(&z->mpz, &a->mpz, mpz_get_ui(&b->mpz));
787 return (object *)z;
788} /* mpz_lshift() */
789
790static object *
791mpz_rshift(a, b)
792 mpzobject *a;
793 mpzobject *b;
794{
795 int cmpres;
796 mpzobject *z;
797
798
799 if ((cmpres = mpz_cmp_ui(&b->mpz, (unsigned long int)0)) == 0) {
800 /* a >> 0 == a */
801 INCREF(a);
802 return (object *)a;
803 }
804
805 if (cmpres < 0) {
806 err_setstr(ValueError, "mpz.>> negative shift count");
807 return NULL;
808 }
809
810 if (mpz_size(&b->mpz) > 1)
811 return (object *)err_nomem();
812
813 if ((z = newmpzobject()) == NULL)
814 return NULL;
815
816 mpz_div_2exp(&z->mpz, &a->mpz, mpz_get_ui(&b->mpz));
817 return (object *)z;
818} /* mpz_rshift() */
819
820static object *
821mpz_andfunc(a, b)
822 mpzobject *a;
823 mpzobject *b;
824{
825 mpzobject *z;
826
827
828 if ((z = newmpzobject()) == NULL)
829 return NULL;
830
831 mpz_and(&z->mpz, &a->mpz, &b->mpz);
832 return (object *)z;
833} /* mpz_andfunc() */
834
835/* hack Hack HAck HACk HACK, XXX this code is dead slow */
836void
837mpz_xor(res, op1, op2)
838 MP_INT *res;
839 const MP_INT *op1;
840 const MP_INT *op2;
841{
842 MP_INT tmpmpz;
843
844 mpz_init(&tmpmpz);
845
846 mpz_and(res, op1, op2);
847 mpz_com(&tmpmpz, res);
848 mpz_ior(res, op1, op2);
849 mpz_and(res, res, &tmpmpz);
850
851 mpz_clear(&tmpmpz);
852} /* mpz_xor() HACK */
853
854static object *
855mpz_xorfunc(a, b)
856 mpzobject *a;
857 mpzobject *b;
858{
859 mpzobject *z;
860
861
862 if ((z = newmpzobject()) == NULL)
863 return NULL;
864
865 mpz_xor(&z->mpz, &a->mpz, &b->mpz);
866 return (object *)z;
867} /* mpz_xorfunc() */
868
869static object *
870mpz_orfunc(a, b)
871 mpzobject *a;
872 mpzobject *b;
873{
874 mpzobject *z;
875
876
877 if ((z = newmpzobject()) == NULL)
878 return NULL;
879
880 mpz_ior(&z->mpz, &a->mpz, &b->mpz);
881 return (object *)z;
882} /* mpz_orfunc() */
883
884/* MPZ initialisation */
885
886#include "longintrepr.h"
887
888static object *
889MPZ_mpz(self, args)
890 object *self;
891 object *args;
892{
893 mpzobject *mpzp;
894 object *objp;
895
896
897#ifdef MPZ_DEBUG
898 fputs("MPZ_mpz() called...\n", stderr);
899#endif /* def MPZ_DEBUG */
900
901 if (!getargs(args, "O", &objp))
902 return NULL;
903
904 /* at least we know it's some object */
905 /* note DON't DECREF args NEITHER objp */
906
907 if (is_intobject(objp)) {
908 long lval;
909
910 if (!getargs(objp, "l", &lval))
911 return NULL;
912
913 if (lval == (long)0) {
914 INCREF(mpz_value_zero);
915 mpzp = mpz_value_zero;
916 }
917 else if (lval == (long)1) {
918 INCREF(mpz_value_one);
919 mpzp = mpz_value_one;
920 }
921 else if ((mpzp = newmpzobject()) == NULL)
922 return NULL;
923 else mpz_set_si(&mpzp->mpz, lval);
924 }
925 else if (is_longobject(objp)) {
926 MP_INT mplongdigit;
927 int i;
928 unsigned char isnegative;
929
930
931 if ((mpzp = newmpzobject()) == NULL)
932 return NULL;
933
934 mpz_set_si(&mpzp->mpz, 0L);
935 mpz_init(&mplongdigit);
936
937 /* how we're gonna handle this? */
Guido van Rossum272841c1996-08-19 23:06:45 +0000938 if ((isnegative = ((i = ((longobject *)objp)->ob_size) < 0) ))
Guido van Rossum5f59d601992-12-14 16:59:51 +0000939 i = -i;
940
941 while (i--) {
942 mpz_set_ui(&mplongdigit,
943 (unsigned long)
944 ((longobject *)objp)->ob_digit[i]);
945 mpz_mul_2exp(&mplongdigit,&mplongdigit,
946 (unsigned long int)i * SHIFT);
947 mpz_ior(&mpzp->mpz, &mpzp->mpz, &mplongdigit);
948 }
949
950 if (isnegative)
951 mpz_neg(&mpzp->mpz, &mpzp->mpz);
952
953 /* get rid of allocation for tmp variable */
954 mpz_clear(&mplongdigit);
955 }
956 else if (is_stringobject(objp)) {
957 char *cp;
958 int len;
959 MP_INT mplongdigit;
960
961 if (!getargs(objp, "s#", &cp, &len))
962 return NULL;
963
964 if ((mpzp = newmpzobject()) == NULL)
965 return NULL;
966
967 mpz_set_si(&mpzp->mpz, 0L);
968 mpz_init(&mplongdigit);
969
970 /* let's do it the same way as with the long conversion:
971 without thinking how it can be faster (-: :-) */
972
973 cp += len;
974 while (len--) {
975 mpz_set_ui(&mplongdigit, (unsigned long)*--cp );
976 mpz_mul_2exp(&mplongdigit,&mplongdigit,
977 (unsigned long int)len * 8);
978 mpz_ior(&mpzp->mpz, &mpzp->mpz, &mplongdigit);
979 }
980
981 /* get rid of allocation for tmp variable */
982 mpz_clear(&mplongdigit);
983 }
984 else if (is_mpzobject(objp)) {
985 INCREF(objp);
986 mpzp = (mpzobject *)objp;
987 }
988 else {
989 err_setstr(TypeError,
990 "mpz.mpz() expects integer, long, string or mpz object argument");
991 return NULL;
992 }
993
994
995#ifdef MPZ_DEBUG
996 fputs("MPZ_mpz: created mpz=", stderr);
997 mpz_out_str(stderr, 10, &mpzp->mpz);
998 putc('\n', stderr);
999#endif /* def MPZ_DEBUG */
1000 return (object *)mpzp;
1001} /* MPZ_mpz() */
1002
1003static mpzobject *
1004mpz_mpzcoerce(z)
1005 object *z;
1006{
1007 /* shortcut: 9 out of 10 times the type is already ok */
1008 if (is_mpzobject(z)) {
1009 INCREF(z);
1010 return (mpzobject *)z; /* coercion succeeded */
1011 }
1012
1013 /* what types do we accept?: intobjects and longobjects */
1014 if (is_intobject(z) || is_longobject(z))
1015 return (mpzobject *)MPZ_mpz((object *)NULL, z);
1016
1017 err_setstr(TypeError, "number coercion (to mpzobject) failed");
1018 return NULL;
1019} /* mpz_mpzcoerce() */
Guido van Rossumb6775db1994-08-01 11:34:53 +00001020
1021/* Forward */
1022static void mpz_divm PROTO((MP_INT *res, const MP_INT *num,
1023 const MP_INT *den, const MP_INT *mod));
Guido van Rossum67a5fdb1993-12-17 12:09:14 +00001024
Guido van Rossum5f59d601992-12-14 16:59:51 +00001025static object *
1026MPZ_powm(self, args)
1027 object *self;
1028 object *args;
1029{
1030 object *base, *exp, *mod;
1031 mpzobject *mpzbase = NULL, *mpzexp = NULL, *mpzmod = NULL;
1032 mpzobject *z;
1033 int tstres;
1034
1035
1036 if (!getargs(args, "(OOO)", &base, &exp, &mod))
1037 return NULL;
1038
1039 if ((mpzbase = mpz_mpzcoerce(base)) == NULL
1040 || (mpzexp = mpz_mpzcoerce(exp)) == NULL
1041 || (mpzmod = mpz_mpzcoerce(mod)) == NULL
1042 || (z = newmpzobject()) == NULL) {
1043 XDECREF(mpzbase);
1044 XDECREF(mpzexp);
1045 XDECREF(mpzmod);
1046 return NULL;
1047 }
1048
1049 if ((tstres=mpz_cmp_ui(&mpzexp->mpz, (unsigned long int)0)) == 0) {
1050 INCREF(mpz_value_one);
1051 return (object *)mpz_value_one;
1052 }
1053
1054 if (tstres < 0) {
1055 MP_INT absexp;
1056 /* negative exp */
1057
1058 mpz_init_set(&absexp, &mpzexp->mpz);
1059 mpz_abs(&absexp, &absexp);
1060 mpz_powm(&z->mpz, &mpzbase->mpz, &absexp, &mpzmod->mpz);
1061
1062 mpz_divm(&z->mpz, &mpz_value_one->mpz, &z->mpz, &mpzmod->mpz);
1063
1064 mpz_clear(&absexp);
1065 }
1066 else {
1067 mpz_powm(&z->mpz, &mpzbase->mpz, &mpzexp->mpz, &mpzmod->mpz);
1068 }
1069
1070 DECREF(mpzbase);
1071 DECREF(mpzexp);
1072 DECREF(mpzmod);
1073
1074 return (object *)z;
1075} /* MPZ_powm() */
1076
1077
1078static object *
1079MPZ_gcd(self, args)
1080 object *self;
1081 object *args;
1082{
1083 object *op1, *op2;
1084 mpzobject *mpzop1 = NULL, *mpzop2 = NULL;
1085 mpzobject *z;
1086
1087
1088 if (!getargs(args, "(OO)", &op1, &op2))
1089 return NULL;
1090
1091 if ((mpzop1 = mpz_mpzcoerce(op1)) == NULL
1092 || (mpzop2 = mpz_mpzcoerce(op2)) == NULL
1093 || (z = newmpzobject()) == NULL) {
1094 XDECREF(mpzop1);
1095 XDECREF(mpzop2);
1096 return NULL;
1097 }
1098
1099 /* ok, we have three mpzobjects, and an initialised result holder */
1100 mpz_gcd(&z->mpz, &mpzop1->mpz, &mpzop2->mpz);
1101
1102 DECREF(mpzop1);
1103 DECREF(mpzop2);
1104
1105 return (object *)z;
1106} /* MPZ_gcd() */
1107
1108
1109static object *
1110MPZ_gcdext(self, args)
1111 object *self;
1112 object *args;
1113{
1114 object *op1, *op2, *z = NULL;
1115 mpzobject *mpzop1 = NULL, *mpzop2 = NULL;
1116 mpzobject *g = NULL, *s = NULL, *t = NULL;
1117
1118
1119 if (!getargs(args, "(OO)", &op1, &op2))
1120 return NULL;
1121
1122 if ((mpzop1 = mpz_mpzcoerce(op1)) == NULL
1123 || (mpzop2 = mpz_mpzcoerce(op2)) == NULL
1124 || (z = newtupleobject(3)) == NULL
1125 || (g = newmpzobject()) == NULL
1126 || (s = newmpzobject()) == NULL
1127 || (t = newmpzobject()) == NULL) {
1128 XDECREF(mpzop1);
1129 XDECREF(mpzop2);
1130 XDECREF(z);
1131 XDECREF(g);
1132 XDECREF(s);
1133 /*XDECREF(t);*/
1134 return NULL;
1135 }
1136
1137 mpz_gcdext(&g->mpz, &s->mpz, &t->mpz, &mpzop1->mpz, &mpzop2->mpz);
1138
1139 DECREF(mpzop1);
1140 DECREF(mpzop2);
1141
1142 (void)settupleitem(z, 0, (object *)g);
1143 (void)settupleitem(z, 1, (object *)s);
1144 (void)settupleitem(z, 2, (object *)t);
1145
1146 return (object *)z;
1147} /* MPZ_gcdext() */
1148
1149
1150static object *
1151MPZ_sqrt(self, args)
1152 object *self;
1153 object *args;
1154{
1155 object *op;
1156 mpzobject *mpzop = NULL;
1157 mpzobject *z;
1158
1159
1160 if (!getargs(args, "O", &op))
1161 return NULL;
1162
1163 if ((mpzop = mpz_mpzcoerce(op)) == NULL
1164 || (z = newmpzobject()) == NULL) {
1165 XDECREF(mpzop);
1166 return NULL;
1167 }
1168
1169 mpz_sqrt(&z->mpz, &mpzop->mpz);
1170
1171 DECREF(mpzop);
1172
1173 return (object *)z;
1174} /* MPZ_sqrt() */
1175
1176
1177static object *
1178MPZ_sqrtrem(self, args)
1179 object *self;
1180 object *args;
1181{
1182 object *op, *z = NULL;
1183 mpzobject *mpzop = NULL;
1184 mpzobject *root = NULL, *rem = NULL;
1185
1186
1187 if (!getargs(args, "O", &op))
1188 return NULL;
1189
1190 if ((mpzop = mpz_mpzcoerce(op)) == NULL
1191 || (z = newtupleobject(2)) == NULL
1192 || (root = newmpzobject()) == NULL
1193 || (rem = newmpzobject()) == NULL) {
1194 XDECREF(mpzop);
1195 XDECREF(z);
1196 XDECREF(root);
1197 /*XDECREF(rem);*/
1198 return NULL;
1199 }
1200
1201 mpz_sqrtrem(&root->mpz, &rem->mpz, &mpzop->mpz);
1202
1203 DECREF(mpzop);
1204
1205 (void)settupleitem(z, 0, (object *)root);
1206 (void)settupleitem(z, 1, (object *)rem);
1207
1208 return (object *)z;
1209} /* MPZ_sqrtrem() */
1210
1211
Guido van Rossum67a5fdb1993-12-17 12:09:14 +00001212static void
Guido van Rossum5f59d601992-12-14 16:59:51 +00001213#if __STDC__
1214mpz_divm(MP_INT *res, const MP_INT *num, const MP_INT *den, const MP_INT *mod)
1215#else
1216mpz_divm(res, num, den, mod)
1217 MP_INT *res;
1218 const MP_INT *num;
1219 const MP_INT *den;
1220 const MP_INT *mod;
1221#endif
1222{
1223 MP_INT s0, s1, q, r, x, d0, d1;
1224
1225 mpz_init_set(&s0, num);
1226 mpz_init_set_ui(&s1, 0);
1227 mpz_init(&q);
1228 mpz_init(&r);
1229 mpz_init(&x);
1230 mpz_init_set(&d0, den);
1231 mpz_init_set(&d1, mod);
1232
Guido van Rossum272841c1996-08-19 23:06:45 +00001233#ifdef GMP2
1234 while (d1._mp_size != 0) {
1235#else
Guido van Rossum5f59d601992-12-14 16:59:51 +00001236 while (d1.size != 0) {
Guido van Rossum272841c1996-08-19 23:06:45 +00001237#endif
Guido van Rossum5f59d601992-12-14 16:59:51 +00001238 mpz_divmod(&q, &r, &d0, &d1);
1239 mpz_set(&d0, &d1);
1240 mpz_set(&d1, &r);
1241
1242 mpz_mul(&x, &s1, &q);
1243 mpz_sub(&x, &s0, &x);
1244 mpz_set(&s0, &s1);
1245 mpz_set(&s1, &x);
1246 }
1247
Guido van Rossum272841c1996-08-19 23:06:45 +00001248#ifdef GMP2
1249 if (d0._mp_size != 1 || d0._mp_d[0] != 1)
1250 res->_mp_size = 0; /* trouble: the gcd != 1; set s to zero */
1251#else
Guido van Rossum5f59d601992-12-14 16:59:51 +00001252 if (d0.size != 1 || d0.d[0] != 1)
1253 res->size = 0; /* trouble: the gcd != 1; set s to zero */
Guido van Rossum272841c1996-08-19 23:06:45 +00001254#endif
Guido van Rossum5f59d601992-12-14 16:59:51 +00001255 else {
1256#ifdef MPZ_MDIV_BUG
1257 /* watch out here! first check the signs, and then perform
1258 the mpz_mod() since mod could point to res */
1259 if ((s0.size < 0) != (mod->size < 0)) {
1260 mpz_mod(res, &s0, mod);
1261
1262 if (res->size)
1263 mpz_add(res, res, mod);
1264 }
1265 else
1266 mpz_mod(res, &s0, mod);
1267
1268#else /* def MPZ_MDIV_BUG */
1269 mpz_mmod(res, &s0, mod);
1270#endif /* def MPZ_MDIV_BUG else */
1271 }
1272
1273 mpz_clear(&s0);
1274 mpz_clear(&s1);
1275 mpz_clear(&q);
1276 mpz_clear(&r);
1277 mpz_clear(&x);
1278 mpz_clear(&d0);
1279 mpz_clear(&d1);
1280} /* mpz_divm() */
1281
1282
1283static object *
1284MPZ_divm(self, args)
1285 object *self;
1286 object *args;
1287{
1288 object *num, *den, *mod;
1289 mpzobject *mpznum, *mpzden, *mpzmod = NULL;
1290 mpzobject *z = NULL;
1291
1292
1293 if (!getargs(args, "(OOO)", &num, &den, &mod))
1294 return NULL;
1295
1296 if ((mpznum = mpz_mpzcoerce(num)) == NULL
1297 || (mpzden = mpz_mpzcoerce(den)) == NULL
1298 || (mpzmod = mpz_mpzcoerce(mod)) == NULL
1299 || (z = newmpzobject()) == NULL ) {
1300 XDECREF(mpznum);
1301 XDECREF(mpzden);
1302 XDECREF(mpzmod);
1303 return NULL;
1304 }
1305
1306 mpz_divm(&z->mpz, &mpznum->mpz, &mpzden->mpz, &mpzmod->mpz);
1307
1308 DECREF(mpznum);
1309 DECREF(mpzden);
1310 DECREF(mpzmod);
1311
1312 if (mpz_cmp_ui(&z->mpz, (unsigned long int)0) == 0) {
1313 DECREF(z);
1314 err_setstr(ValueError, "gcd(den, mod) != 1 or num == 0");
1315 return NULL;
1316 }
1317
1318 return (object *)z;
1319} /* MPZ_divm() */
1320
1321
1322/* MPZ methods-as-attributes */
1323#ifdef MPZ_CONVERSIONS_AS_METHODS
1324static object *
1325mpz_int(self, args)
1326 mpzobject *self;
1327 object *args;
1328#else /* def MPZ_CONVERSIONS_AS_METHODS */
1329static object *
1330mpz_int(self)
1331 mpzobject *self;
1332#endif /* def MPZ_CONVERSIONS_AS_METHODS else */
1333{
1334 long sli;
1335
1336
1337#ifdef MPZ_CONVERSIONS_AS_METHODS
1338 if (!getnoarg(args))
1339 return NULL;
1340#endif /* def MPZ_CONVERSIONS_AS_METHODS */
1341
1342 if (mpz_size(&self->mpz) > 1
1343 || (sli = (long)mpz_get_ui(&self->mpz)) < (long)0 ) {
1344 err_setstr(ValueError, "mpz.int() arg too long to convert");
1345 return NULL;
1346 }
1347
1348 if (mpz_cmp_ui(&self->mpz, (unsigned long)0) < 0)
1349 sli = -sli;
1350
1351 return newintobject(sli);
1352} /* mpz_int() */
1353
1354static object *
1355#ifdef MPZ_CONVERSIONS_AS_METHODS
1356mpz_long(self, args)
1357 mpzobject *self;
1358 object *args;
1359#else /* def MPZ_CONVERSIONS_AS_METHODS */
1360mpz_long(self)
1361 mpzobject *self;
1362#endif /* def MPZ_CONVERSIONS_AS_METHODS else */
1363{
1364 int i, isnegative;
1365 unsigned long int uli;
1366 longobject *longobjp;
1367 int ldcount;
1368 int bitpointer, newbitpointer;
1369 MP_INT mpzscratch;
1370
1371
1372#ifdef MPZ_CONVERSIONS_AS_METHODS
1373 if (!getnoarg(args))
1374 return NULL;
1375#endif /* def MPZ_CONVERSIONS_AS_METHODS */
1376
1377 /* determine length of python-long to be allocated */
1378 if ((longobjp = alloclongobject(i = (int)
1379 ((mpz_size(&self->mpz) * BITS_PER_MP_LIMB
1380 + SHIFT - 1) /
1381 SHIFT))) == NULL)
1382 return NULL;
1383
1384 /* determine sign, and copy self to scratch var */
1385 mpz_init_set(&mpzscratch, &self->mpz);
Guido van Rossum272841c1996-08-19 23:06:45 +00001386 if ((isnegative = (mpz_cmp_ui(&self->mpz, (unsigned long int)0) < 0)))
Guido van Rossum5f59d601992-12-14 16:59:51 +00001387 mpz_neg(&mpzscratch, &mpzscratch);
1388
1389 /* let those bits come, let those bits go,
1390 e.g. dismantle mpzscratch, build longobject */
1391
1392 bitpointer = 0; /* the number of valid bits in stock */
1393 newbitpointer = 0;
1394 ldcount = 0; /* the python-long limb counter */
1395 uli = (unsigned long int)0;
1396 while (i--) {
1397 longobjp->ob_digit[ldcount] = uli & MASK;
1398
1399 /* check if we've had enough bits for this digit */
1400 if (bitpointer < SHIFT) {
1401 uli = mpz_get_ui(&mpzscratch);
1402 longobjp->ob_digit[ldcount] |=
1403 (uli << bitpointer) & MASK;
1404 uli >>= SHIFT-bitpointer;
1405 bitpointer += BITS_PER_MP_LIMB;
1406 mpz_div_2exp(&mpzscratch, &mpzscratch,
1407 BITS_PER_MP_LIMB);
1408 }
1409 else
1410 uli >>= SHIFT;
1411 bitpointer -= SHIFT;
1412 ldcount++;
1413 }
1414
1415 assert(mpz_cmp_ui(&mpzscratch, (unsigned long int)0) == 0);
1416 mpz_clear(&mpzscratch);
1417 assert(ldcount <= longobjp->ob_size);
1418
1419 /* long_normalize() is file-static */
1420 /* longobjp = long_normalize(longobjp); */
1421 while (ldcount > 0 && longobjp->ob_digit[ldcount-1] == 0)
1422 ldcount--;
1423 longobjp->ob_size = ldcount;
1424
1425
1426 if (isnegative)
1427 longobjp->ob_size = -longobjp->ob_size;
1428
1429 return (object *)longobjp;
1430
1431} /* mpz_long() */
1432
1433
1434/* I would have avoided pow() anyways, so ... */
1435static const double multiplier = 256.0 * 256.0 * 256.0 * 256.0;
1436
1437#ifdef MPZ_CONVERSIONS_AS_METHODS
1438static object *
1439mpz_float(self, args)
1440 mpzobject *self;
1441 object *args;
1442#else /* def MPZ_CONVERSIONS_AS_METHODS */
1443static object *
1444mpz_float(self)
1445 mpzobject *self;
1446#endif /* def MPZ_CONVERSIONS_AS_METHODS else */
1447{
1448 int i, isnegative;
1449 double x;
1450 double mulstate;
1451 MP_INT mpzscratch;
1452
1453
1454#ifdef MPZ_CONVERSIONS_AS_METHODS
1455 if (!getnoarg(args))
1456 return NULL;
1457#endif /* def MPZ_CONVERSIONS_AS_METHODS */
1458
1459 i = (int)mpz_size(&self->mpz);
1460
1461 /* determine sign, and copy abs(self) to scratch var */
Guido van Rossum272841c1996-08-19 23:06:45 +00001462 if ((isnegative = (mpz_cmp_ui(&self->mpz, (unsigned long int)0) < 0))) {
Guido van Rossum5f59d601992-12-14 16:59:51 +00001463 mpz_init(&mpzscratch);
1464 mpz_neg(&mpzscratch, &self->mpz);
1465 }
1466 else
1467 mpz_init_set(&mpzscratch, &self->mpz);
1468
1469 /* let those bits come, let those bits go,
1470 e.g. dismantle mpzscratch, build floatobject */
1471
1472 x = 0.0;
1473 mulstate = 1.0;
1474 while (i--) {
1475 x += mulstate * mpz_get_ui(&mpzscratch);
1476 mulstate *= multiplier;
1477 mpz_div_2exp(&mpzscratch, &mpzscratch, BITS_PER_MP_LIMB);
1478 }
1479
1480 assert(mpz_cmp_ui(&mpzscratch, (unsigned long int)0) == 0);
1481 mpz_clear(&mpzscratch);
1482
1483 if (isnegative)
1484 x = -x;
1485
1486 return newfloatobject(x);
1487
1488} /* mpz_float() */
1489
1490#ifdef MPZ_CONVERSIONS_AS_METHODS
1491static object *
1492mpz_hex(self, args)
1493 mpzobject *self;
1494 object *args;
1495#else /* def MPZ_CONVERSIONS_AS_METHODS */
1496static object *
1497mpz_hex(self)
1498 mpzobject *self;
1499#endif /* def MPZ_CONVERSIONS_AS_METHODS else */
1500{
1501#ifdef MPZ_CONVERSIONS_AS_METHODS
1502 if (!getnoarg(args))
1503 return NULL;
1504#endif /* def MPZ_CONVERSIONS_AS_METHODS */
1505
1506 return mpz_format(self, 16, (unsigned char)1);
1507} /* mpz_hex() */
1508
1509#ifdef MPZ_CONVERSIONS_AS_METHODS
1510static object *
1511mpz_oct(self, args)
1512 mpzobject *self;
1513 object *args;
1514#else /* def MPZ_CONVERSIONS_AS_METHODS */
1515static object *
1516mpz_oct(self)
1517 mpzobject *self;
1518#endif /* def MPZ_CONVERSIONS_AS_METHODS else */
1519{
1520#ifdef MPZ_CONVERSIONS_AS_METHODS
1521 if (!getnoarg(args))
1522 return NULL;
1523#endif /* def MPZ_CONVERSIONS_AS_METHODS */
1524
1525 return mpz_format(self, 8, (unsigned char)1);
1526} /* mpz_oct() */
1527
1528static object *
1529mpz_binary(self, args)
1530 mpzobject *self;
1531 object *args;
1532{
1533 int size;
1534 stringobject *strobjp;
1535 char *cp;
1536 MP_INT mp;
1537 unsigned long ldigit;
1538
1539 if (!getnoarg(args))
1540 return NULL;
1541
1542 if (mpz_cmp_ui(&self->mpz, (unsigned long int)0) < 0) {
1543 err_setstr(ValueError, "mpz.binary() arg must be >= 0");
1544 return NULL;
1545 }
1546
1547 mpz_init_set(&mp, &self->mpz);
1548 size = (int)mpz_size(&mp);
1549
1550 if ((strobjp = (stringobject *)
1551 newsizedstringobject((char *)0,
1552 size * sizeof (unsigned long int))) == NULL)
1553 return NULL;
1554
1555 /* get the beginning of the string memory and start copying things */
1556 cp = GETSTRINGVALUE(strobjp);
1557
1558 /* this has been programmed using a (fairly) decent lib-i/f it could
1559 be must faster if we looked into the GMP lib */
1560 while (size--) {
1561 ldigit = mpz_get_ui(&mp);
1562 mpz_div_2exp(&mp, &mp, BITS_PER_MP_LIMB);
1563 *cp++ = (unsigned char)(ldigit & 0xFF);
1564 *cp++ = (unsigned char)((ldigit >>= 8) & 0xFF);
1565 *cp++ = (unsigned char)((ldigit >>= 8) & 0xFF);
1566 *cp++ = (unsigned char)((ldigit >>= 8) & 0xFF);
1567 }
1568
1569 while (strobjp->ob_size && !*--cp)
1570 strobjp->ob_size--;
1571
1572 return (object *)strobjp;
1573} /* mpz_binary() */
1574
1575
1576static struct methodlist mpz_methods[] = {
1577#ifdef MPZ_CONVERSIONS_AS_METHODS
1578 {"int", mpz_int},
1579 {"long", mpz_long},
1580 {"float", mpz_float},
1581 {"hex", mpz_hex},
1582 {"oct", mpz_oct},
1583#endif /* def MPZ_CONVERSIONS_AS_METHODS */
Guido van Rossumb6775db1994-08-01 11:34:53 +00001584 {"binary", (object *(*)(object *, object *))mpz_binary},
Guido van Rossum5f59d601992-12-14 16:59:51 +00001585 {NULL, NULL} /* sentinel */
1586};
1587
1588static object *
1589mpz_getattr(self, name)
1590 mpzobject *self;
1591 char *name;
1592{
1593 return findmethod(mpz_methods, (object *)self, name);
1594} /* mpz_getattr() */
1595
1596
1597static int
1598mpz_coerce(pv, pw)
1599 object **pv;
1600 object **pw;
1601{
1602 object *z;
1603
1604#ifdef MPZ_DEBUG
1605 fputs("mpz_coerce() called...\n", stderr);
1606#endif /* def MPZ_DEBUG */
1607
1608 assert(is_mpzobject(*pv));
1609
1610 /* always convert other arg to mpz value, except for floats */
1611 if (!is_floatobject(*pw)) {
1612 if ((z = (object *)mpz_mpzcoerce(*pw)) == NULL)
1613 return -1; /* -1: an error always has been set */
1614
1615 INCREF(*pv);
1616 *pw = z;
1617 }
1618 else {
1619 if ((z = mpz_float(*pv, NULL)) == NULL)
1620 return -1;
1621
1622 INCREF(*pw);
1623 *pv = z;
1624 }
1625 return 0; /* coercion succeeded */
1626
1627} /* mpz_coerce() */
1628
1629
1630static object *
1631mpz_repr(v)
1632 object *v;
1633{
1634 return mpz_format(v, 10, (unsigned char)1);
1635} /* mpz_repr() */
1636
1637
1638
Guido van Rossumb6775db1994-08-01 11:34:53 +00001639#define UF (unaryfunc)
1640#define BF (binaryfunc)
Guido van Rossum3bbc62e1995-01-02 19:30:30 +00001641#define TF (ternaryfunc)
Guido van Rossumb6775db1994-08-01 11:34:53 +00001642#define IF (inquiry)
1643#define CF (coercion)
Guido van Rossum5f59d601992-12-14 16:59:51 +00001644
1645static number_methods mpz_as_number = {
1646 BF mpz_addition, /*nb_add*/
1647 BF mpz_substract, /*nb_subtract*/
1648 BF mpz_multiply, /*nb_multiply*/
1649 BF mpz_divide, /*nb_divide*/
1650 BF mpz_remainder, /*nb_remainder*/
1651 BF mpz_div_and_mod, /*nb_divmod*/
Guido van Rossum3bbc62e1995-01-02 19:30:30 +00001652 TF mpz_power, /*nb_power*/
Guido van Rossum5f59d601992-12-14 16:59:51 +00001653 UF mpz_negative, /*nb_negative*/
1654 UF mpz_positive, /*tp_positive*/
1655 UF mpz_absolute, /*tp_absolute*/
1656 IF mpz_nonzero, /*tp_nonzero*/
Guido van Rossum272841c1996-08-19 23:06:45 +00001657 UF py_mpz_invert, /*nb_invert*/
Guido van Rossum5f59d601992-12-14 16:59:51 +00001658 BF mpz_lshift, /*nb_lshift*/
1659 BF mpz_rshift, /*nb_rshift*/
1660 BF mpz_andfunc, /*nb_and*/
1661 BF mpz_xorfunc, /*nb_xor*/
1662 BF mpz_orfunc, /*nb_or*/
Guido van Rossumb6775db1994-08-01 11:34:53 +00001663 CF mpz_coerce, /*nb_coerce*/
Guido van Rossum5f59d601992-12-14 16:59:51 +00001664#ifndef MPZ_CONVERSIONS_AS_METHODS
1665 UF mpz_int, /*nb_int*/
1666 UF mpz_long, /*nb_long*/
1667 UF mpz_float, /*nb_float*/
1668 UF mpz_oct, /*nb_oct*/
1669 UF mpz_hex, /*nb_hex*/
1670#endif /* ndef MPZ_CONVERSIONS_AS_METHODS */
1671};
1672
1673static typeobject MPZtype = {
1674 OB_HEAD_INIT(&Typetype)
1675 0, /*ob_size*/
1676 "mpz", /*tp_name*/
1677 sizeof(mpzobject), /*tp_size*/
1678 0, /*tp_itemsize*/
1679 /* methods */
Guido van Rossumb6775db1994-08-01 11:34:53 +00001680 (destructor)mpz_dealloc, /*tp_dealloc*/
1681 0, /*tp_print*/
1682 (getattrfunc)mpz_getattr, /*tp_getattr*/
1683 0, /*tp_setattr*/
1684 (cmpfunc)mpz_compare, /*tp_compare*/
1685 (reprfunc)mpz_repr, /*tp_repr*/
1686 &mpz_as_number, /*tp_as_number*/
Guido van Rossum5f59d601992-12-14 16:59:51 +00001687};
1688
1689/* List of functions exported by this module */
1690
1691static struct methodlist mpz_functions[] = {
1692#if 0
1693 {initialiser_name, MPZ_mpz},
1694#else /* 0 */
1695 /* until guido ``fixes'' struct methodlist */
1696 {(char *)initialiser_name, MPZ_mpz},
1697#endif /* 0 else */
1698 {"powm", MPZ_powm},
1699 {"gcd", MPZ_gcd},
1700 {"gcdext", MPZ_gcdext},
1701 {"sqrt", MPZ_sqrt},
1702 {"sqrtrem", MPZ_sqrtrem},
1703 {"divm", MPZ_divm},
1704 {NULL, NULL} /* Sentinel */
1705};
1706
1707
1708/* #define MP_TEST_ALLOC */
1709
1710#ifdef MP_TEST_ALLOC
1711#define MP_TEST_SIZE 4
1712static const char mp_test_magic[MP_TEST_SIZE] = {'\xAA','\xAA','\xAA','\xAA'};
1713static mp_test_error( location )
1714 int *location;
1715{
1716 /* assumptions: *alloc returns address dividable by 4,
1717 mpz_* routines allocate in chunks dividable by four */
1718 fprintf(stderr, "MP_TEST_ERROR: location holds 0x%08d\n", *location );
1719 fatal("MP_TEST_ERROR");
1720} /* static mp_test_error() */
1721#define MP_EXTRA_ALLOC(size) ((size) + MP_TEST_SIZE)
1722#define MP_SET_TEST(basep,size) (void)memcpy( ((char *)(basep))+(size), mp_test_magic, MP_TEST_SIZE)
1723#define MP_DO_TEST(basep,size) if ( !memcmp( ((char *)(basep))+(size), mp_test_magic, MP_TEST_SIZE ) ) \
1724 ; \
1725 else \
1726 mp_test_error((int *)((char *)(basep) + size))
1727#else /* def MP_TEST_ALLOC */
1728#define MP_EXTRA_ALLOC(size) (size)
1729#define MP_SET_TEST(basep,size)
1730#define MP_DO_TEST(basep,size)
1731#endif /* def MP_TEST_ALLOC else */
1732
1733void *mp_allocate( alloc_size )
1734 size_t alloc_size;
1735{
1736 void *res;
1737
1738#ifdef MPZ_DEBUG
1739 fprintf(stderr, "mp_allocate : size %ld\n",
1740 alloc_size);
1741#endif /* def MPZ_DEBUG */
1742
1743 if ( (res = malloc(MP_EXTRA_ALLOC(alloc_size))) == NULL )
1744 fatal("mp_allocate failure");
1745
1746#ifdef MPZ_DEBUG
1747 fprintf(stderr, "mp_allocate : address 0x%08x\n", res);
1748#endif /* def MPZ_DEBUG */
1749
1750 MP_SET_TEST(res,alloc_size);
1751
1752 return res;
1753} /* mp_allocate() */
1754
1755
1756void *mp_reallocate( ptr, old_size, new_size )
1757 void *ptr;
1758 size_t old_size;
1759 size_t new_size;
1760{
1761 void *res;
1762
1763#ifdef MPZ_DEBUG
1764 fprintf(stderr, "mp_reallocate: old address 0x%08x, old size %ld\n",
1765 ptr, old_size);
1766#endif /* def MPZ_DEBUG */
1767
1768 MP_DO_TEST(ptr, old_size);
1769
1770 if ( (res = realloc(ptr, MP_EXTRA_ALLOC(new_size))) == NULL )
1771 fatal("mp_reallocate failure");
1772
1773#ifdef MPZ_DEBUG
1774 fprintf(stderr, "mp_reallocate: new address 0x%08x, new size %ld\n",
1775 res, new_size);
1776#endif /* def MPZ_DEBUG */
1777
1778 MP_SET_TEST(res, new_size);
1779
1780 return res;
1781} /* mp_reallocate() */
1782
1783
1784void mp_free( ptr, size )
1785 void *ptr;
1786 size_t size;
1787{
1788
1789#ifdef MPZ_DEBUG
1790 fprintf(stderr, "mp_free : old address 0x%08x, old size %ld\n",
1791 ptr, size);
1792#endif /* def MPZ_DEBUG */
1793
1794 MP_DO_TEST(ptr, size);
1795 free(ptr);
1796} /* mp_free() */
1797
1798
1799
1800/* Initialize this module. */
1801
1802void
1803initmpz()
1804{
1805#ifdef MPZ_DEBUG
1806 fputs( "initmpz() called...\n", stderr );
1807#endif /* def MPZ_DEBUG */
1808
1809 mp_set_memory_functions( mp_allocate, mp_reallocate, mp_free );
1810 (void)initmodule("mpz", mpz_functions);
1811
1812 /* create some frequently used constants */
1813 if ((mpz_value_zero = newmpzobject()) == NULL)
Guido van Rossum3bbc62e1995-01-02 19:30:30 +00001814 fatal("initmpz: can't initialize mpz constants");
Guido van Rossum5f59d601992-12-14 16:59:51 +00001815 mpz_set_ui(&mpz_value_zero->mpz, (unsigned long int)0);
1816
1817 if ((mpz_value_one = newmpzobject()) == NULL)
Guido van Rossum3bbc62e1995-01-02 19:30:30 +00001818 fatal("initmpz: can't initialize mpz constants");
Guido van Rossum5f59d601992-12-14 16:59:51 +00001819 mpz_set_ui(&mpz_value_one->mpz, (unsigned long int)1);
1820
1821 if ((mpz_value_mone = newmpzobject()) == NULL)
Guido van Rossum3bbc62e1995-01-02 19:30:30 +00001822 fatal("initmpz: can't initialize mpz constants");
Guido van Rossum5f59d601992-12-14 16:59:51 +00001823 mpz_set_si(&mpz_value_mone->mpz, (long)-1);
1824
1825} /* initmpz() */
1826#ifdef MAKEDUMMYINT
1827int _mpz_dummy_int; /* XXX otherwise, we're .bss-less (DYNLOAD->Jack?) */
1828#endif /* def MAKEDUMMYINT */