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