blob: d0b9d7f9a9aa69509f9675a93c21009b2fc76c3a [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() */
Guido van Rossum67a5fdb1993-12-17 12:09:14 +0000996
997static void mpz_divm();
998
Guido van Rossum5f59d601992-12-14 16:59:51 +0000999static object *
1000MPZ_powm(self, args)
1001 object *self;
1002 object *args;
1003{
1004 object *base, *exp, *mod;
1005 mpzobject *mpzbase = NULL, *mpzexp = NULL, *mpzmod = NULL;
1006 mpzobject *z;
1007 int tstres;
1008
1009
1010 if (!getargs(args, "(OOO)", &base, &exp, &mod))
1011 return NULL;
1012
1013 if ((mpzbase = mpz_mpzcoerce(base)) == NULL
1014 || (mpzexp = mpz_mpzcoerce(exp)) == NULL
1015 || (mpzmod = mpz_mpzcoerce(mod)) == NULL
1016 || (z = newmpzobject()) == NULL) {
1017 XDECREF(mpzbase);
1018 XDECREF(mpzexp);
1019 XDECREF(mpzmod);
1020 return NULL;
1021 }
1022
1023 if ((tstres=mpz_cmp_ui(&mpzexp->mpz, (unsigned long int)0)) == 0) {
1024 INCREF(mpz_value_one);
1025 return (object *)mpz_value_one;
1026 }
1027
1028 if (tstres < 0) {
1029 MP_INT absexp;
1030 /* negative exp */
1031
1032 mpz_init_set(&absexp, &mpzexp->mpz);
1033 mpz_abs(&absexp, &absexp);
1034 mpz_powm(&z->mpz, &mpzbase->mpz, &absexp, &mpzmod->mpz);
1035
1036 mpz_divm(&z->mpz, &mpz_value_one->mpz, &z->mpz, &mpzmod->mpz);
1037
1038 mpz_clear(&absexp);
1039 }
1040 else {
1041 mpz_powm(&z->mpz, &mpzbase->mpz, &mpzexp->mpz, &mpzmod->mpz);
1042 }
1043
1044 DECREF(mpzbase);
1045 DECREF(mpzexp);
1046 DECREF(mpzmod);
1047
1048 return (object *)z;
1049} /* MPZ_powm() */
1050
1051
1052static object *
1053MPZ_gcd(self, args)
1054 object *self;
1055 object *args;
1056{
1057 object *op1, *op2;
1058 mpzobject *mpzop1 = NULL, *mpzop2 = NULL;
1059 mpzobject *z;
1060
1061
1062 if (!getargs(args, "(OO)", &op1, &op2))
1063 return NULL;
1064
1065 if ((mpzop1 = mpz_mpzcoerce(op1)) == NULL
1066 || (mpzop2 = mpz_mpzcoerce(op2)) == NULL
1067 || (z = newmpzobject()) == NULL) {
1068 XDECREF(mpzop1);
1069 XDECREF(mpzop2);
1070 return NULL;
1071 }
1072
1073 /* ok, we have three mpzobjects, and an initialised result holder */
1074 mpz_gcd(&z->mpz, &mpzop1->mpz, &mpzop2->mpz);
1075
1076 DECREF(mpzop1);
1077 DECREF(mpzop2);
1078
1079 return (object *)z;
1080} /* MPZ_gcd() */
1081
1082
1083static object *
1084MPZ_gcdext(self, args)
1085 object *self;
1086 object *args;
1087{
1088 object *op1, *op2, *z = NULL;
1089 mpzobject *mpzop1 = NULL, *mpzop2 = NULL;
1090 mpzobject *g = NULL, *s = NULL, *t = NULL;
1091
1092
1093 if (!getargs(args, "(OO)", &op1, &op2))
1094 return NULL;
1095
1096 if ((mpzop1 = mpz_mpzcoerce(op1)) == NULL
1097 || (mpzop2 = mpz_mpzcoerce(op2)) == NULL
1098 || (z = newtupleobject(3)) == NULL
1099 || (g = newmpzobject()) == NULL
1100 || (s = newmpzobject()) == NULL
1101 || (t = newmpzobject()) == NULL) {
1102 XDECREF(mpzop1);
1103 XDECREF(mpzop2);
1104 XDECREF(z);
1105 XDECREF(g);
1106 XDECREF(s);
1107 /*XDECREF(t);*/
1108 return NULL;
1109 }
1110
1111 mpz_gcdext(&g->mpz, &s->mpz, &t->mpz, &mpzop1->mpz, &mpzop2->mpz);
1112
1113 DECREF(mpzop1);
1114 DECREF(mpzop2);
1115
1116 (void)settupleitem(z, 0, (object *)g);
1117 (void)settupleitem(z, 1, (object *)s);
1118 (void)settupleitem(z, 2, (object *)t);
1119
1120 return (object *)z;
1121} /* MPZ_gcdext() */
1122
1123
1124static object *
1125MPZ_sqrt(self, args)
1126 object *self;
1127 object *args;
1128{
1129 object *op;
1130 mpzobject *mpzop = NULL;
1131 mpzobject *z;
1132
1133
1134 if (!getargs(args, "O", &op))
1135 return NULL;
1136
1137 if ((mpzop = mpz_mpzcoerce(op)) == NULL
1138 || (z = newmpzobject()) == NULL) {
1139 XDECREF(mpzop);
1140 return NULL;
1141 }
1142
1143 mpz_sqrt(&z->mpz, &mpzop->mpz);
1144
1145 DECREF(mpzop);
1146
1147 return (object *)z;
1148} /* MPZ_sqrt() */
1149
1150
1151static object *
1152MPZ_sqrtrem(self, args)
1153 object *self;
1154 object *args;
1155{
1156 object *op, *z = NULL;
1157 mpzobject *mpzop = NULL;
1158 mpzobject *root = NULL, *rem = NULL;
1159
1160
1161 if (!getargs(args, "O", &op))
1162 return NULL;
1163
1164 if ((mpzop = mpz_mpzcoerce(op)) == NULL
1165 || (z = newtupleobject(2)) == NULL
1166 || (root = newmpzobject()) == NULL
1167 || (rem = newmpzobject()) == NULL) {
1168 XDECREF(mpzop);
1169 XDECREF(z);
1170 XDECREF(root);
1171 /*XDECREF(rem);*/
1172 return NULL;
1173 }
1174
1175 mpz_sqrtrem(&root->mpz, &rem->mpz, &mpzop->mpz);
1176
1177 DECREF(mpzop);
1178
1179 (void)settupleitem(z, 0, (object *)root);
1180 (void)settupleitem(z, 1, (object *)rem);
1181
1182 return (object *)z;
1183} /* MPZ_sqrtrem() */
1184
1185
Guido van Rossum67a5fdb1993-12-17 12:09:14 +00001186static void
Guido van Rossum5f59d601992-12-14 16:59:51 +00001187#if __STDC__
1188mpz_divm(MP_INT *res, const MP_INT *num, const MP_INT *den, const MP_INT *mod)
1189#else
1190mpz_divm(res, num, den, mod)
1191 MP_INT *res;
1192 const MP_INT *num;
1193 const MP_INT *den;
1194 const MP_INT *mod;
1195#endif
1196{
1197 MP_INT s0, s1, q, r, x, d0, d1;
1198
1199 mpz_init_set(&s0, num);
1200 mpz_init_set_ui(&s1, 0);
1201 mpz_init(&q);
1202 mpz_init(&r);
1203 mpz_init(&x);
1204 mpz_init_set(&d0, den);
1205 mpz_init_set(&d1, mod);
1206
1207 while (d1.size != 0) {
1208 mpz_divmod(&q, &r, &d0, &d1);
1209 mpz_set(&d0, &d1);
1210 mpz_set(&d1, &r);
1211
1212 mpz_mul(&x, &s1, &q);
1213 mpz_sub(&x, &s0, &x);
1214 mpz_set(&s0, &s1);
1215 mpz_set(&s1, &x);
1216 }
1217
1218 if (d0.size != 1 || d0.d[0] != 1)
1219 res->size = 0; /* trouble: the gcd != 1; set s to zero */
1220 else {
1221#ifdef MPZ_MDIV_BUG
1222 /* watch out here! first check the signs, and then perform
1223 the mpz_mod() since mod could point to res */
1224 if ((s0.size < 0) != (mod->size < 0)) {
1225 mpz_mod(res, &s0, mod);
1226
1227 if (res->size)
1228 mpz_add(res, res, mod);
1229 }
1230 else
1231 mpz_mod(res, &s0, mod);
1232
1233#else /* def MPZ_MDIV_BUG */
1234 mpz_mmod(res, &s0, mod);
1235#endif /* def MPZ_MDIV_BUG else */
1236 }
1237
1238 mpz_clear(&s0);
1239 mpz_clear(&s1);
1240 mpz_clear(&q);
1241 mpz_clear(&r);
1242 mpz_clear(&x);
1243 mpz_clear(&d0);
1244 mpz_clear(&d1);
1245} /* mpz_divm() */
1246
1247
1248static object *
1249MPZ_divm(self, args)
1250 object *self;
1251 object *args;
1252{
1253 object *num, *den, *mod;
1254 mpzobject *mpznum, *mpzden, *mpzmod = NULL;
1255 mpzobject *z = NULL;
1256
1257
1258 if (!getargs(args, "(OOO)", &num, &den, &mod))
1259 return NULL;
1260
1261 if ((mpznum = mpz_mpzcoerce(num)) == NULL
1262 || (mpzden = mpz_mpzcoerce(den)) == NULL
1263 || (mpzmod = mpz_mpzcoerce(mod)) == NULL
1264 || (z = newmpzobject()) == NULL ) {
1265 XDECREF(mpznum);
1266 XDECREF(mpzden);
1267 XDECREF(mpzmod);
1268 return NULL;
1269 }
1270
1271 mpz_divm(&z->mpz, &mpznum->mpz, &mpzden->mpz, &mpzmod->mpz);
1272
1273 DECREF(mpznum);
1274 DECREF(mpzden);
1275 DECREF(mpzmod);
1276
1277 if (mpz_cmp_ui(&z->mpz, (unsigned long int)0) == 0) {
1278 DECREF(z);
1279 err_setstr(ValueError, "gcd(den, mod) != 1 or num == 0");
1280 return NULL;
1281 }
1282
1283 return (object *)z;
1284} /* MPZ_divm() */
1285
1286
1287/* MPZ methods-as-attributes */
1288#ifdef MPZ_CONVERSIONS_AS_METHODS
1289static object *
1290mpz_int(self, args)
1291 mpzobject *self;
1292 object *args;
1293#else /* def MPZ_CONVERSIONS_AS_METHODS */
1294static object *
1295mpz_int(self)
1296 mpzobject *self;
1297#endif /* def MPZ_CONVERSIONS_AS_METHODS else */
1298{
1299 long sli;
1300
1301
1302#ifdef MPZ_CONVERSIONS_AS_METHODS
1303 if (!getnoarg(args))
1304 return NULL;
1305#endif /* def MPZ_CONVERSIONS_AS_METHODS */
1306
1307 if (mpz_size(&self->mpz) > 1
1308 || (sli = (long)mpz_get_ui(&self->mpz)) < (long)0 ) {
1309 err_setstr(ValueError, "mpz.int() arg too long to convert");
1310 return NULL;
1311 }
1312
1313 if (mpz_cmp_ui(&self->mpz, (unsigned long)0) < 0)
1314 sli = -sli;
1315
1316 return newintobject(sli);
1317} /* mpz_int() */
1318
1319static object *
1320#ifdef MPZ_CONVERSIONS_AS_METHODS
1321mpz_long(self, args)
1322 mpzobject *self;
1323 object *args;
1324#else /* def MPZ_CONVERSIONS_AS_METHODS */
1325mpz_long(self)
1326 mpzobject *self;
1327#endif /* def MPZ_CONVERSIONS_AS_METHODS else */
1328{
1329 int i, isnegative;
1330 unsigned long int uli;
1331 longobject *longobjp;
1332 int ldcount;
1333 int bitpointer, newbitpointer;
1334 MP_INT mpzscratch;
1335
1336
1337#ifdef MPZ_CONVERSIONS_AS_METHODS
1338 if (!getnoarg(args))
1339 return NULL;
1340#endif /* def MPZ_CONVERSIONS_AS_METHODS */
1341
1342 /* determine length of python-long to be allocated */
1343 if ((longobjp = alloclongobject(i = (int)
1344 ((mpz_size(&self->mpz) * BITS_PER_MP_LIMB
1345 + SHIFT - 1) /
1346 SHIFT))) == NULL)
1347 return NULL;
1348
1349 /* determine sign, and copy self to scratch var */
1350 mpz_init_set(&mpzscratch, &self->mpz);
1351 if (isnegative = (mpz_cmp_ui(&self->mpz, (unsigned long int)0) < 0))
1352 mpz_neg(&mpzscratch, &mpzscratch);
1353
1354 /* let those bits come, let those bits go,
1355 e.g. dismantle mpzscratch, build longobject */
1356
1357 bitpointer = 0; /* the number of valid bits in stock */
1358 newbitpointer = 0;
1359 ldcount = 0; /* the python-long limb counter */
1360 uli = (unsigned long int)0;
1361 while (i--) {
1362 longobjp->ob_digit[ldcount] = uli & MASK;
1363
1364 /* check if we've had enough bits for this digit */
1365 if (bitpointer < SHIFT) {
1366 uli = mpz_get_ui(&mpzscratch);
1367 longobjp->ob_digit[ldcount] |=
1368 (uli << bitpointer) & MASK;
1369 uli >>= SHIFT-bitpointer;
1370 bitpointer += BITS_PER_MP_LIMB;
1371 mpz_div_2exp(&mpzscratch, &mpzscratch,
1372 BITS_PER_MP_LIMB);
1373 }
1374 else
1375 uli >>= SHIFT;
1376 bitpointer -= SHIFT;
1377 ldcount++;
1378 }
1379
1380 assert(mpz_cmp_ui(&mpzscratch, (unsigned long int)0) == 0);
1381 mpz_clear(&mpzscratch);
1382 assert(ldcount <= longobjp->ob_size);
1383
1384 /* long_normalize() is file-static */
1385 /* longobjp = long_normalize(longobjp); */
1386 while (ldcount > 0 && longobjp->ob_digit[ldcount-1] == 0)
1387 ldcount--;
1388 longobjp->ob_size = ldcount;
1389
1390
1391 if (isnegative)
1392 longobjp->ob_size = -longobjp->ob_size;
1393
1394 return (object *)longobjp;
1395
1396} /* mpz_long() */
1397
1398
1399/* I would have avoided pow() anyways, so ... */
1400static const double multiplier = 256.0 * 256.0 * 256.0 * 256.0;
1401
1402#ifdef MPZ_CONVERSIONS_AS_METHODS
1403static object *
1404mpz_float(self, args)
1405 mpzobject *self;
1406 object *args;
1407#else /* def MPZ_CONVERSIONS_AS_METHODS */
1408static object *
1409mpz_float(self)
1410 mpzobject *self;
1411#endif /* def MPZ_CONVERSIONS_AS_METHODS else */
1412{
1413 int i, isnegative;
1414 double x;
1415 double mulstate;
1416 MP_INT mpzscratch;
1417
1418
1419#ifdef MPZ_CONVERSIONS_AS_METHODS
1420 if (!getnoarg(args))
1421 return NULL;
1422#endif /* def MPZ_CONVERSIONS_AS_METHODS */
1423
1424 i = (int)mpz_size(&self->mpz);
1425
1426 /* determine sign, and copy abs(self) to scratch var */
1427 if (isnegative = (mpz_cmp_ui(&self->mpz, (unsigned long int)0) < 0)) {
1428 mpz_init(&mpzscratch);
1429 mpz_neg(&mpzscratch, &self->mpz);
1430 }
1431 else
1432 mpz_init_set(&mpzscratch, &self->mpz);
1433
1434 /* let those bits come, let those bits go,
1435 e.g. dismantle mpzscratch, build floatobject */
1436
1437 x = 0.0;
1438 mulstate = 1.0;
1439 while (i--) {
1440 x += mulstate * mpz_get_ui(&mpzscratch);
1441 mulstate *= multiplier;
1442 mpz_div_2exp(&mpzscratch, &mpzscratch, BITS_PER_MP_LIMB);
1443 }
1444
1445 assert(mpz_cmp_ui(&mpzscratch, (unsigned long int)0) == 0);
1446 mpz_clear(&mpzscratch);
1447
1448 if (isnegative)
1449 x = -x;
1450
1451 return newfloatobject(x);
1452
1453} /* mpz_float() */
1454
1455#ifdef MPZ_CONVERSIONS_AS_METHODS
1456static object *
1457mpz_hex(self, args)
1458 mpzobject *self;
1459 object *args;
1460#else /* def MPZ_CONVERSIONS_AS_METHODS */
1461static object *
1462mpz_hex(self)
1463 mpzobject *self;
1464#endif /* def MPZ_CONVERSIONS_AS_METHODS else */
1465{
1466#ifdef MPZ_CONVERSIONS_AS_METHODS
1467 if (!getnoarg(args))
1468 return NULL;
1469#endif /* def MPZ_CONVERSIONS_AS_METHODS */
1470
1471 return mpz_format(self, 16, (unsigned char)1);
1472} /* mpz_hex() */
1473
1474#ifdef MPZ_CONVERSIONS_AS_METHODS
1475static object *
1476mpz_oct(self, args)
1477 mpzobject *self;
1478 object *args;
1479#else /* def MPZ_CONVERSIONS_AS_METHODS */
1480static object *
1481mpz_oct(self)
1482 mpzobject *self;
1483#endif /* def MPZ_CONVERSIONS_AS_METHODS else */
1484{
1485#ifdef MPZ_CONVERSIONS_AS_METHODS
1486 if (!getnoarg(args))
1487 return NULL;
1488#endif /* def MPZ_CONVERSIONS_AS_METHODS */
1489
1490 return mpz_format(self, 8, (unsigned char)1);
1491} /* mpz_oct() */
1492
1493static object *
1494mpz_binary(self, args)
1495 mpzobject *self;
1496 object *args;
1497{
1498 int size;
1499 stringobject *strobjp;
1500 char *cp;
1501 MP_INT mp;
1502 unsigned long ldigit;
1503
1504 if (!getnoarg(args))
1505 return NULL;
1506
1507 if (mpz_cmp_ui(&self->mpz, (unsigned long int)0) < 0) {
1508 err_setstr(ValueError, "mpz.binary() arg must be >= 0");
1509 return NULL;
1510 }
1511
1512 mpz_init_set(&mp, &self->mpz);
1513 size = (int)mpz_size(&mp);
1514
1515 if ((strobjp = (stringobject *)
1516 newsizedstringobject((char *)0,
1517 size * sizeof (unsigned long int))) == NULL)
1518 return NULL;
1519
1520 /* get the beginning of the string memory and start copying things */
1521 cp = GETSTRINGVALUE(strobjp);
1522
1523 /* this has been programmed using a (fairly) decent lib-i/f it could
1524 be must faster if we looked into the GMP lib */
1525 while (size--) {
1526 ldigit = mpz_get_ui(&mp);
1527 mpz_div_2exp(&mp, &mp, BITS_PER_MP_LIMB);
1528 *cp++ = (unsigned char)(ldigit & 0xFF);
1529 *cp++ = (unsigned char)((ldigit >>= 8) & 0xFF);
1530 *cp++ = (unsigned char)((ldigit >>= 8) & 0xFF);
1531 *cp++ = (unsigned char)((ldigit >>= 8) & 0xFF);
1532 }
1533
1534 while (strobjp->ob_size && !*--cp)
1535 strobjp->ob_size--;
1536
1537 return (object *)strobjp;
1538} /* mpz_binary() */
1539
1540
1541static struct methodlist mpz_methods[] = {
1542#ifdef MPZ_CONVERSIONS_AS_METHODS
1543 {"int", mpz_int},
1544 {"long", mpz_long},
1545 {"float", mpz_float},
1546 {"hex", mpz_hex},
1547 {"oct", mpz_oct},
1548#endif /* def MPZ_CONVERSIONS_AS_METHODS */
Guido van Rossum67a5fdb1993-12-17 12:09:14 +00001549 {"binary", (object * (*) (object *, object *)) mpz_binary},
Guido van Rossum5f59d601992-12-14 16:59:51 +00001550 {NULL, NULL} /* sentinel */
1551};
1552
1553static object *
1554mpz_getattr(self, name)
1555 mpzobject *self;
1556 char *name;
1557{
1558 return findmethod(mpz_methods, (object *)self, name);
1559} /* mpz_getattr() */
1560
1561
1562static int
1563mpz_coerce(pv, pw)
1564 object **pv;
1565 object **pw;
1566{
1567 object *z;
1568
1569#ifdef MPZ_DEBUG
1570 fputs("mpz_coerce() called...\n", stderr);
1571#endif /* def MPZ_DEBUG */
1572
1573 assert(is_mpzobject(*pv));
1574
1575 /* always convert other arg to mpz value, except for floats */
1576 if (!is_floatobject(*pw)) {
1577 if ((z = (object *)mpz_mpzcoerce(*pw)) == NULL)
1578 return -1; /* -1: an error always has been set */
1579
1580 INCREF(*pv);
1581 *pw = z;
1582 }
1583 else {
1584 if ((z = mpz_float(*pv, NULL)) == NULL)
1585 return -1;
1586
1587 INCREF(*pw);
1588 *pv = z;
1589 }
1590 return 0; /* coercion succeeded */
1591
1592} /* mpz_coerce() */
1593
1594
1595static object *
1596mpz_repr(v)
1597 object *v;
1598{
1599 return mpz_format(v, 10, (unsigned char)1);
1600} /* mpz_repr() */
1601
1602
1603
1604#define UF (object* (*) FPROTO((object *))) /* Unary function */
1605#define BF (object* (*) FPROTO((object *, object *))) /* Binary function */
1606#define IF (int (*) FPROTO((object *))) /* Int function */
1607
1608static number_methods mpz_as_number = {
1609 BF mpz_addition, /*nb_add*/
1610 BF mpz_substract, /*nb_subtract*/
1611 BF mpz_multiply, /*nb_multiply*/
1612 BF mpz_divide, /*nb_divide*/
1613 BF mpz_remainder, /*nb_remainder*/
1614 BF mpz_div_and_mod, /*nb_divmod*/
1615 BF mpz_power, /*nb_power*/
1616 UF mpz_negative, /*nb_negative*/
1617 UF mpz_positive, /*tp_positive*/
1618 UF mpz_absolute, /*tp_absolute*/
1619 IF mpz_nonzero, /*tp_nonzero*/
1620 UF mpz_invert, /*nb_invert*/
1621 BF mpz_lshift, /*nb_lshift*/
1622 BF mpz_rshift, /*nb_rshift*/
1623 BF mpz_andfunc, /*nb_and*/
1624 BF mpz_xorfunc, /*nb_xor*/
1625 BF mpz_orfunc, /*nb_or*/
1626 (int (*) FPROTO((object **, object **)))
1627 mpz_coerce, /*nb_coerce*/
1628#ifndef MPZ_CONVERSIONS_AS_METHODS
1629 UF mpz_int, /*nb_int*/
1630 UF mpz_long, /*nb_long*/
1631 UF mpz_float, /*nb_float*/
1632 UF mpz_oct, /*nb_oct*/
1633 UF mpz_hex, /*nb_hex*/
1634#endif /* ndef MPZ_CONVERSIONS_AS_METHODS */
1635};
1636
1637static typeobject MPZtype = {
1638 OB_HEAD_INIT(&Typetype)
1639 0, /*ob_size*/
1640 "mpz", /*tp_name*/
1641 sizeof(mpzobject), /*tp_size*/
1642 0, /*tp_itemsize*/
1643 /* methods */
Guido van Rossum67a5fdb1993-12-17 12:09:14 +00001644 (void (*) (object *)) mpz_dealloc, /*tp_dealloc*/
Guido van Rossumc6004111993-11-05 10:22:19 +00001645 0, /*tp_print*/
Guido van Rossum67a5fdb1993-12-17 12:09:14 +00001646 (object * (*)(object *, char *)) mpz_getattr, /*tp_getattr*/
Guido van Rossum5f59d601992-12-14 16:59:51 +00001647 0, /*tp_setattr*/
Guido van Rossum67a5fdb1993-12-17 12:09:14 +00001648 (int (*) (object *, object *)) mpz_compare, /*tp_compare*/
Guido van Rossum5f59d601992-12-14 16:59:51 +00001649 mpz_repr, /*tp_repr*/
1650 &mpz_as_number, /*tp_as_number*/
1651};
1652
1653/* List of functions exported by this module */
1654
1655static struct methodlist mpz_functions[] = {
1656#if 0
1657 {initialiser_name, MPZ_mpz},
1658#else /* 0 */
1659 /* until guido ``fixes'' struct methodlist */
1660 {(char *)initialiser_name, MPZ_mpz},
1661#endif /* 0 else */
1662 {"powm", MPZ_powm},
1663 {"gcd", MPZ_gcd},
1664 {"gcdext", MPZ_gcdext},
1665 {"sqrt", MPZ_sqrt},
1666 {"sqrtrem", MPZ_sqrtrem},
1667 {"divm", MPZ_divm},
1668 {NULL, NULL} /* Sentinel */
1669};
1670
1671
1672/* #define MP_TEST_ALLOC */
1673
1674#ifdef MP_TEST_ALLOC
1675#define MP_TEST_SIZE 4
1676static const char mp_test_magic[MP_TEST_SIZE] = {'\xAA','\xAA','\xAA','\xAA'};
1677static mp_test_error( location )
1678 int *location;
1679{
1680 /* assumptions: *alloc returns address dividable by 4,
1681 mpz_* routines allocate in chunks dividable by four */
1682 fprintf(stderr, "MP_TEST_ERROR: location holds 0x%08d\n", *location );
1683 fatal("MP_TEST_ERROR");
1684} /* static mp_test_error() */
1685#define MP_EXTRA_ALLOC(size) ((size) + MP_TEST_SIZE)
1686#define MP_SET_TEST(basep,size) (void)memcpy( ((char *)(basep))+(size), mp_test_magic, MP_TEST_SIZE)
1687#define MP_DO_TEST(basep,size) if ( !memcmp( ((char *)(basep))+(size), mp_test_magic, MP_TEST_SIZE ) ) \
1688 ; \
1689 else \
1690 mp_test_error((int *)((char *)(basep) + size))
1691#else /* def MP_TEST_ALLOC */
1692#define MP_EXTRA_ALLOC(size) (size)
1693#define MP_SET_TEST(basep,size)
1694#define MP_DO_TEST(basep,size)
1695#endif /* def MP_TEST_ALLOC else */
1696
1697void *mp_allocate( alloc_size )
1698 size_t alloc_size;
1699{
1700 void *res;
1701
1702#ifdef MPZ_DEBUG
1703 fprintf(stderr, "mp_allocate : size %ld\n",
1704 alloc_size);
1705#endif /* def MPZ_DEBUG */
1706
1707 if ( (res = malloc(MP_EXTRA_ALLOC(alloc_size))) == NULL )
1708 fatal("mp_allocate failure");
1709
1710#ifdef MPZ_DEBUG
1711 fprintf(stderr, "mp_allocate : address 0x%08x\n", res);
1712#endif /* def MPZ_DEBUG */
1713
1714 MP_SET_TEST(res,alloc_size);
1715
1716 return res;
1717} /* mp_allocate() */
1718
1719
1720void *mp_reallocate( ptr, old_size, new_size )
1721 void *ptr;
1722 size_t old_size;
1723 size_t new_size;
1724{
1725 void *res;
1726
1727#ifdef MPZ_DEBUG
1728 fprintf(stderr, "mp_reallocate: old address 0x%08x, old size %ld\n",
1729 ptr, old_size);
1730#endif /* def MPZ_DEBUG */
1731
1732 MP_DO_TEST(ptr, old_size);
1733
1734 if ( (res = realloc(ptr, MP_EXTRA_ALLOC(new_size))) == NULL )
1735 fatal("mp_reallocate failure");
1736
1737#ifdef MPZ_DEBUG
1738 fprintf(stderr, "mp_reallocate: new address 0x%08x, new size %ld\n",
1739 res, new_size);
1740#endif /* def MPZ_DEBUG */
1741
1742 MP_SET_TEST(res, new_size);
1743
1744 return res;
1745} /* mp_reallocate() */
1746
1747
1748void mp_free( ptr, size )
1749 void *ptr;
1750 size_t size;
1751{
1752
1753#ifdef MPZ_DEBUG
1754 fprintf(stderr, "mp_free : old address 0x%08x, old size %ld\n",
1755 ptr, size);
1756#endif /* def MPZ_DEBUG */
1757
1758 MP_DO_TEST(ptr, size);
1759 free(ptr);
1760} /* mp_free() */
1761
1762
1763
1764/* Initialize this module. */
1765
1766void
1767initmpz()
1768{
1769#ifdef MPZ_DEBUG
1770 fputs( "initmpz() called...\n", stderr );
1771#endif /* def MPZ_DEBUG */
1772
1773 mp_set_memory_functions( mp_allocate, mp_reallocate, mp_free );
1774 (void)initmodule("mpz", mpz_functions);
1775
1776 /* create some frequently used constants */
1777 if ((mpz_value_zero = newmpzobject()) == NULL)
1778 fatal("initmpz: can't initialize mpz contstants");
1779 mpz_set_ui(&mpz_value_zero->mpz, (unsigned long int)0);
1780
1781 if ((mpz_value_one = newmpzobject()) == NULL)
1782 fatal("initmpz: can't initialize mpz contstants");
1783 mpz_set_ui(&mpz_value_one->mpz, (unsigned long int)1);
1784
1785 if ((mpz_value_mone = newmpzobject()) == NULL)
1786 fatal("initmpz: can't initialize mpz contstants");
1787 mpz_set_si(&mpz_value_mone->mpz, (long)-1);
1788
1789} /* initmpz() */
1790#ifdef MAKEDUMMYINT
1791int _mpz_dummy_int; /* XXX otherwise, we're .bss-less (DYNLOAD->Jack?) */
1792#endif /* def MAKEDUMMYINT */