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