Annotation of OpenXM_contrib/gmp/demos/perl/GMP.xs, Revision 1.1.1.1
1.1 ohara 1: /* GMP module external subroutines.
2:
3: Copyright 2001 Free Software Foundation, Inc.
4:
5: This file is part of the GNU MP Library.
6:
7: The GNU MP Library is free software; you can redistribute it and/or modify
8: it under the terms of the GNU Lesser General Public License as published by
9: the Free Software Foundation; either version 2.1 of the License, or (at your
10: option) any later version.
11:
12: The GNU MP Library is distributed in the hope that it will be useful, but
13: WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14: or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
15: License for more details.
16:
17: You should have received a copy of the GNU Lesser General Public License
18: along with the GNU MP Library; see the file COPYING.LIB. If not, write to
19: the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
20: MA 02111-1307, USA. */
21:
22:
23: /* Notes:
24:
25: Routines are grouped with the alias feature and a table of function
26: pointers where possible, since each xsub routine ends up with quite a bit
27: of overhead. Different combinations of arguments and return values have
28: to be separate though.
29:
30: The "INTERFACE:" feature isn't available in perl 5.005 and so isn't used.
31: "ALIAS:" requires a table lookup with CvXSUBANY(cv).any_i32 (which is
32: "ix") whereas "INTERFACE:" would have CvXSUBANY(cv).any_dptr as the
33: function pointer immediately.
34:
35: Mixed-type swapped-order assignments like "$a = 123; $a += mpz(456);"
36: invoke the plain overloaded "+", not "+=", which makes life easier.
37:
38: The various mpz_assume types are used with the overloaded operators since
39: we know they always pass a class object as the first argument and we can
40: save an sv_derived_from() lookup. There's assert()s in MPX_ASSUME() to
41: check though.
42:
43: The overload_constant routines reached via overload::constant get 4
44: arguments in perl 5.6, not the 3 as documented. This is apparently a
45: bug, using "..." lets us ignore the extra one.
46:
47: There's only a few "si" functions in gmp, so generally SvIV values get
48: handled with an mpz_set_si into a temporary and then a full precision mpz
49: routine. This is reasonably efficient.
50:
51: Strings are identified with "SvPOK(sv)||SvPOKp(sv)" so that magic
52: SVt_PVLV returns from substr() will work. SvPV() always gives a plain
53: actual string.
54:
55: Bugs:
56:
57: Should IV's and/or NV's be identified with the same dual test as for
58: strings?
59:
60: The memory leak detection attempted in GMP::END() doesn't work when mpz's
61: are created as constants because END() is called before they're
62: destroyed. What's the right place to hook such a check? */
63:
64:
65: /* Comment this out to get assertion checking. */
66: #define NDEBUG
67:
68: /* Change this to "#define TRACE(x) x" for some diagnostics. */
69: #define TRACE(x)
70:
71:
72: #include <assert.h>
73: #include <float.h>
74:
75: #include "EXTERN.h"
76: #include "perl.h"
77: #include "XSUB.h"
78: #include "patchlevel.h"
79:
80: #include "gmp.h"
81:
82:
83: /* Code which doesn't check anything itself, but exists to support other
84: assert()s. */
85: #ifdef NDEBUG
86: #define assert_support(x)
87: #else
88: #define assert_support(x) x
89: #endif
90:
91: /* sv_derived_from etc in 5.005 took "char *" rather than "const char *".
92: Avoid some compiler warnings by using const only where it works. */
93: #if PERL_REVISION > 5 || (PERL_REVISION == 5 && PERL_VERSION >= 6)
94: #define classconst const
95: #else
96: #define classconst
97: #endif
98:
99: #define GMP_MALLOC_ID 42
100:
101: static classconst char mpz_class[] = "GMP::Mpz";
102: static classconst char mpq_class[] = "GMP::Mpq";
103: static classconst char mpf_class[] = "GMP::Mpf";
104: static classconst char rand_class[] = "GMP::Rand";
105:
106:
107: assert_support (static long mpz_count = 0;)
108: assert_support (static long mpq_count = 0;)
109: assert_support (static long mpf_count = 0;)
110: assert_support (static long rand_count = 0;)
111:
112: #define TRACE_ACTIVE() \
113: assert_support \
114: (TRACE (printf (" active %ld mpz, %ld mpq, %ld mpf, %ld randstate\n", \
115: mpz_count, mpq_count, mpf_count, rand_count)))
116:
117:
118: /* Each "struct mpz_elem" etc is an mpz_t with a link field tacked on the
119: end so they can be held on a linked list. */
120:
121: #define CREATE_MPX(type) \
122: \
123: /* must have mpz_t etc first, for sprintf below */ \
124: struct type##_elem { \
125: type##_t m; \
126: struct type##_elem *next; \
127: }; \
128: typedef struct type##_elem *type; \
129: typedef struct type##_elem *type##_assume; \
130: typedef type##_ptr type##_coerce; \
131: typedef type##_ptr type##_mutate; \
132: \
133: static type type##_freelist = NULL; \
134: \
135: static type \
136: new_##type (void) \
137: { \
138: type p; \
139: TRACE (printf ("new %s\n", type##_class)); \
140: if (type##_freelist != NULL) \
141: { \
142: p = type##_freelist; \
143: type##_freelist = type##_freelist->next; \
144: } \
145: else \
146: { \
147: New (GMP_MALLOC_ID, p, 1, struct type##_elem); \
148: type##_init (p->m); \
149: } \
150: TRACE (printf (" p=%p\n", p)); \
151: assert_support (type##_count++); \
152: TRACE_ACTIVE (); \
153: return p; \
154: } \
155:
156: CREATE_MPX (mpz)
157: CREATE_MPX (mpq)
158:
159: typedef mpf_ptr mpf;
160: typedef mpf_ptr mpf_assume;
161: typedef mpf_ptr mpf_coerce_st0;
162: typedef mpf_ptr mpf_coerce_def;
163:
164:
165: static mpf
166: new_mpf (unsigned long prec)
167: {
168: mpf p;
169: New (GMP_MALLOC_ID, p, 1, __mpf_struct);
170: mpf_init2 (p, prec);
171: TRACE (printf (" mpf p=%p\n", p));
172: assert_support (mpf_count++);
173: TRACE_ACTIVE ();
174: return p;
175: }
176:
177:
178: /* tmp_mpf_t records an allocated precision with an mpf_t so changes of
179: precision can be done with just an mpf_set_prec_raw. */
180:
181: struct tmp_mpf_struct {
182: mpf_t m;
183: unsigned long allocated_prec;
184: };
185: typedef const struct tmp_mpf_struct *tmp_mpf_srcptr;
186: typedef struct tmp_mpf_struct *tmp_mpf_ptr;
187: typedef struct tmp_mpf_struct tmp_mpf_t[1];
188:
189: #define tmp_mpf_init(f) \
190: do { \
191: mpf_init (f->m); \
192: f->allocated_prec = mpf_get_prec (f->m); \
193: } while (0)
194:
195: static void
196: tmp_mpf_grow (tmp_mpf_ptr f, unsigned long prec)
197: {
198: mpf_set_prec_raw (f->m, f->allocated_prec);
199: mpf_set_prec (f->m, prec);
200: f->allocated_prec = mpf_get_prec (f->m);
201: }
202:
203: #define tmp_mpf_shrink(f) tmp_mpf_grow (f, 1L)
204:
205: #define tmp_mpf_set_prec(f,prec) \
206: do { \
207: if (prec > f->allocated_prec) \
208: tmp_mpf_grow (f, prec); \
209: else \
210: mpf_set_prec_raw (f->m, prec); \
211: } while (0)
212:
213:
214: static mpz_t tmp_mpz_0, tmp_mpz_1, tmp_mpz_2;
215: static mpq_t tmp_mpq_0, tmp_mpq_1;
216: static tmp_mpf_t tmp_mpf_0, tmp_mpf_1;
217:
218:
219: #define FREE_MPX_FREELIST(p,type) \
220: do { \
221: TRACE (printf ("free %s\n", type##_class)); \
222: p->next = type##_freelist; \
223: type##_freelist = p; \
224: assert_support (type##_count--); \
225: TRACE_ACTIVE (); \
226: assert (type##_count >= 0); \
227: } while (0)
228:
229: /* this version for comparison, if desired */
230: #define FREE_MPX_NOFREELIST(p,type) \
231: do { \
232: TRACE (printf ("free %s\n", type##_class)); \
233: type##_clear (p->m); \
234: Safefree (p); \
235: assert_support (type##_count--); \
236: TRACE_ACTIVE (); \
237: assert (type##_count >= 0); \
238: } while (0)
239:
240: #define free_mpz(z) FREE_MPX_FREELIST (z, mpz)
241: #define free_mpq(q) FREE_MPX_FREELIST (q, mpq)
242:
243:
244: /* Aliases for use in typemaps */
245: typedef char *malloced_string;
246: typedef const char *const_string;
247: typedef const char *const_string_assume;
248: typedef char *string;
249: typedef SV *order_noswap;
250: typedef SV *dummy;
251: typedef SV *SV_copy_0;
252: typedef unsigned long ulong_coerce;
253: typedef __gmp_randstate_struct *randstate;
254:
255: #define SvMPX(s,type) ((type) SvIV((SV*) SvRV(s)))
256: #define SvMPZ(s) SvMPX(s,mpz)
257: #define SvMPQ(s) SvMPX(s,mpq)
258: #define SvMPF(s) SvMPX(s,mpf)
259: #define SvRANDSTATE(s) SvMPX(s,randstate)
260:
261: #define MPX_ASSUME(x,sv,type) \
262: do { \
263: assert (sv_derived_from (sv, type##_class)); \
264: x = SvMPX(sv,type); \
265: } while (0)
266:
267: #define MPZ_ASSUME(z,sv) MPX_ASSUME(z,sv,mpz)
268: #define MPQ_ASSUME(q,sv) MPX_ASSUME(q,sv,mpq)
269: #define MPF_ASSUME(f,sv) MPX_ASSUME(f,sv,mpf)
270:
271: #define numberof(x) (sizeof (x) / sizeof ((x)[0]))
272: #define SGN(x) ((x)<0 ? -1 : (x) != 0)
273: #define ABS(x) ((x)>=0 ? (x) : -(x))
274: #define double_integer_p(d) (floor (d) == (d))
275:
276: #define x_mpq_integer_p(q) \
277: (mpz_cmp_ui (mpq_denref(q), 1L) == 0)
278: #define x_mpq_equal_si(q,n,d) \
279: (mpz_cmp_si (mpq_numref(q), n) == 0 && mpz_cmp_ui (mpq_denref(q), d) == 0)
280: #define x_mpq_equal_z(q,z) \
281: (x_mpq_integer_p(q) && mpz_cmp (mpq_numref(q), z) == 0)
282:
283: #define assert_table(ix) assert (ix >= 0 && ix < numberof (table))
284:
285: #define SV_PTR_SWAP(x,y) \
286: do { SV *__tmp = (x); (x) = (y); (y) = __tmp; } while (0)
287: #define MPF_PTR_SWAP(x,y) \
288: do { mpf_ptr __tmp = (x); (x) = (y); (y) = __tmp; } while (0)
289:
290: #define SvPOKorp(sv) (SvPOK(sv) || SvPOKp(sv))
291:
292: static void
293: class_or_croak (SV *sv, classconst char *class)
294: {
295: if (! sv_derived_from (sv, class))
296: croak("not type %s", class);
297: }
298:
299:
300: /* These are macros, wrap them in functions. */
301: static int
302: x_mpz_odd_p (mpz_srcptr z)
303: {
304: return mpz_odd_p (z);
305: }
306: static int
307: x_mpz_even_p (mpz_srcptr z)
308: {
309: return mpz_even_p (z);
310: }
311:
312: static void
313: x_mpq_pow_ui (mpq_ptr r, mpq_srcptr b, unsigned long e)
314: {
315: mpz_pow_ui (mpq_numref(r), mpq_numref(b), e);
316: mpz_pow_ui (mpq_denref(r), mpq_denref(b), e);
317: }
318:
319:
320: static void *
321: my_gmp_alloc (size_t n)
322: {
323: void *p;
324: TRACE (printf ("my_gmp_alloc %u\n", n));
325: New (GMP_MALLOC_ID, p, n, char);
326: TRACE (printf (" p=%p\n", p));
327: return p;
328: }
329:
330: static void *
331: my_gmp_realloc (void *p, size_t oldsize, size_t newsize)
332: {
333: TRACE (printf ("my_gmp_realloc %p, %u to %u\n", p, oldsize, newsize));
334: Renew (p, newsize, char);
335: TRACE (printf (" p=%p\n", p));
336: return p;
337: }
338:
339: static void
340: my_gmp_free (void *p, size_t n)
341: {
342: TRACE (printf ("my_gmp_free %p %u\n", p, n));
343: Safefree (p);
344: }
345:
346:
347: #define my_mpx_set_svstr(type) \
348: static void \
349: my_##type##_set_svstr (type##_ptr x, SV *sv) \
350: { \
351: const char *str; \
352: STRLEN len; \
353: TRACE (printf (" my_" #type "_set_svstr\n")); \
354: assert (SvPOKorp (sv)); \
355: str = SvPV (sv, len); \
356: TRACE (printf (" str \"%s\"\n", str)); \
357: if (type##_set_str (x, str, 0) != 0) \
358: croak ("%s: invalid string: %s", type##_class, str); \
359: }
360:
361: my_mpx_set_svstr(mpz)
362: my_mpx_set_svstr(mpq)
363: my_mpx_set_svstr(mpf)
364:
365:
366: /* very slack */
367: static int
368: x_mpq_cmp_si (mpq_srcptr x, long yn, unsigned long yd)
369: {
370: mpq y;
371: int ret;
372: y = new_mpq ();
373: mpq_set_si (y->m, yn, yd);
374: ret = mpq_cmp (x, y->m);
375: free_mpq (y);
376: return ret;
377: }
378:
379: static int
380: x_mpq_fits_slong_p (mpq_srcptr q)
381: {
382: return x_mpq_cmp_si (q, LONG_MIN, 1L) >= 0
383: && mpq_cmp_ui (q, LONG_MAX, 1L) <= 0;
384: }
385:
386: static int
387: x_mpz_cmp_q (mpz_ptr x, mpq_srcptr y)
388: {
389: int ret;
390: mpz_set_ui (mpq_denref(tmp_mpq_0), 1L);
391: mpz_swap (mpq_numref(tmp_mpq_0), x);
392: ret = mpq_cmp (tmp_mpq_0, y);
393: mpz_swap (mpq_numref(tmp_mpq_0), x);
394: return ret;
395: }
396:
397: static int
398: x_mpz_cmp_f (mpz_srcptr x, mpf_srcptr y)
399: {
400: tmp_mpf_set_prec (tmp_mpf_0, mpz_sizeinbase (x, 2));
401: mpf_set_z (tmp_mpf_0->m, x);
402: return mpf_cmp (tmp_mpf_0->m, y);
403: }
404:
405:
406: /* Coerce sv to an mpz. Use tmp to hold the converted value if sv isn't
407: already an mpz (or an mpq of which the numerator can be used). Return
408: the chosen mpz (tmp or the contents of sv). */
409: static mpz_ptr
410: coerce_mpz (mpz_ptr tmp, SV *sv)
411: {
412: if (SvIOK(sv))
413: {
414: mpz_set_si (tmp, SvIVX(sv));
415: return tmp;
416: }
417: if (SvPOKorp(sv))
418: {
419: my_mpz_set_svstr (tmp, sv);
420: return tmp;
421: }
422: if (SvNOK(sv))
423: {
424: double d = SvNVX(sv);
425: if (! double_integer_p (d))
426: croak ("cannot coerce non-integer double to mpz");
427: mpz_set_d (tmp, d);
428: return tmp;
429: }
430: if (SvROK(sv))
431: {
432: if (sv_derived_from (sv, mpz_class))
433: {
434: return SvMPZ(sv)->m;
435: }
436: if (sv_derived_from (sv, mpq_class))
437: {
438: mpq q = SvMPQ(sv);
439: if (! x_mpq_integer_p (q->m))
440: croak ("cannot coerce non-integer mpq to mpz");
441: return mpq_numref(q->m);
442: }
443: if (sv_derived_from (sv, mpf_class))
444: {
445: mpf f = SvMPF(sv);
446: if (! mpf_integer_p (f))
447: croak ("cannot coerce non-integer mpf to mpz");
448: mpz_set_f (tmp, f);
449: return tmp;
450: }
451: }
452: croak ("cannot coerce to mpz");
453: }
454:
455:
456: /* Coerce sv to an mpq. If sv is an mpq then just return that, otherwise
457: use tmp to hold the converted value and return that. */
458: static mpq_ptr
459: coerce_mpq (mpq_ptr tmp, SV *sv)
460: {
461: if (SvIOK(sv))
462: {
463: mpq_set_si (tmp, SvIVX(sv), 1L);
464: return tmp;
465: }
466: if (SvNOK(sv))
467: {
468: mpq_set_d (tmp, SvNVX(sv));
469: return tmp;
470: }
471: if (SvPOKorp(sv))
472: {
473: my_mpq_set_svstr (tmp, sv);
474: return tmp;
475: }
476: if (SvROK(sv))
477: {
478: if (sv_derived_from (sv, mpz_class))
479: {
480: mpq_set_z (tmp, SvMPZ(sv)->m);
481: return tmp;
482: }
483: if (sv_derived_from (sv, mpq_class))
484: {
485: return SvMPQ(sv)->m;
486: }
487: if (sv_derived_from (sv, mpf_class))
488: {
489: mpq_set_f (tmp, SvMPF(sv));
490: return tmp;
491: }
492: }
493: croak ("cannot coerce to mpq");
494: }
495:
496:
497: static void
498: my_mpf_set_sv (mpf_ptr f, SV *sv)
499: {
500: if (SvIOK(sv))
501: mpf_set_si (f, SvIVX(sv));
502: else if (SvPOKorp(sv))
503: my_mpf_set_svstr (f, sv);
504: else if (SvNOK(sv))
505: mpf_set_d (f, SvNVX(sv));
506: else if (SvROK(sv))
507: {
508: if (sv_derived_from (sv, mpz_class))
509: mpf_set_z (f, SvMPZ(sv)->m);
510: else if (sv_derived_from (sv, mpq_class))
511: mpf_set_q (f, SvMPQ(sv)->m);
512: else if (sv_derived_from (sv, mpf_class))
513: mpf_set (f, SvMPF(sv));
514: else
515: goto invalid;
516: }
517: else
518: {
519: invalid:
520: croak ("cannot coerce to mpf");
521: }
522: }
523:
524: /* Coerce sv to an mpf. If sv is an mpf then just return that, otherwise
525: use tmp to hold the converted value (with prec precision). */
526: static mpf_ptr
527: coerce_mpf (tmp_mpf_ptr tmp, SV *sv, unsigned long prec)
528: {
529: if (SvROK(sv) && sv_derived_from (sv, mpf_class))
530: return SvMPF(sv);
531:
532: tmp_mpf_set_prec (tmp, prec);
533: my_mpf_set_sv (tmp->m, sv);
534: return tmp->m;
535: }
536:
537:
538: /* Coerce xv to an mpf and store the pointer in x, ditto for yv to x. If
539: one of xv or yv is an mpf then use it for the precision, otherwise use
540: the default precision. */
541: #define COERCE_MPF_PAIR(prec, x,xv, y,yv) \
542: do { \
543: if (SvROK(xv) && sv_derived_from (xv, mpf_class)) \
544: { \
545: x = SvMPF(xv); \
546: prec = mpf_get_prec (x); \
547: y = coerce_mpf (tmp_mpf_0, yv, prec); \
548: } \
549: else \
550: { \
551: y = coerce_mpf (tmp_mpf_0, yv, mpf_get_default_prec()); \
552: prec = mpf_get_prec (y); \
553: x = coerce_mpf (tmp_mpf_1, xv, prec); \
554: } \
555: } while (0)
556:
557:
558: static unsigned long
559: coerce_ulong (SV *sv)
560: {
561: long n;
562: if (SvIOK(sv))
563: {
564: n = SvIVX(sv);
565: negative_check:
566: if (n < 0)
567: {
568: range_error:
569: croak ("out of range for ulong");
570: }
571: return n;
572: }
573: if (SvNOK(sv))
574: {
575: double d = SvNVX(sv);
576: if (! double_integer_p (d))
577: {
578: integer_error:
579: croak ("not an integer");
580: }
581: n = SvIV(sv);
582: goto negative_check;
583: }
584: if (SvPOKorp(sv))
585: {
586: n = SvIV(sv);
587: goto negative_check;
588: }
589: if (SvROK(sv))
590: {
591: if (sv_derived_from (sv, mpz_class))
592: {
593: mpz z = SvMPZ(sv);
594: if (! mpz_fits_ulong_p (z->m))
595: goto range_error;
596: return mpz_get_ui (z->m);
597: }
598: if (sv_derived_from (sv, mpq_class))
599: {
600: mpq q = SvMPQ(sv);
601: if (! x_mpq_integer_p (q->m))
602: goto integer_error;
603: if (! mpz_fits_ulong_p (mpq_numref (q->m)))
604: goto range_error;
605: return mpz_get_ui (mpq_numref (q->m));
606: }
607: if (sv_derived_from (sv, mpf_class))
608: {
609: mpf f = SvMPF(sv);
610: if (! mpf_integer_p (f))
611: goto integer_error;
612: if (! mpf_fits_ulong_p (f))
613: goto range_error;
614: return mpf_get_ui (f);
615: }
616: }
617: croak ("cannot coerce to ulong");
618: }
619:
620:
621: static long
622: coerce_long (SV *sv)
623: {
624: if (SvIOK(sv))
625: return SvIVX(sv);
626:
627: if (SvNOK(sv))
628: {
629: double d = SvNVX(sv);
630: if (! double_integer_p (d))
631: {
632: integer_error:
633: croak ("not an integer");
634: }
635: return SvIV(sv);
636: }
637:
638: if (SvPOKorp(sv))
639: return SvIV(sv);
640:
641: if (SvROK(sv))
642: {
643: if (sv_derived_from (sv, mpz_class))
644: {
645: mpz z = SvMPZ(sv);
646: if (! mpz_fits_slong_p (z->m))
647: {
648: range_error:
649: croak ("out of range for ulong");
650: }
651: return mpz_get_si (z->m);
652: }
653: if (sv_derived_from (sv, mpq_class))
654: {
655: mpq q = SvMPQ(sv);
656: if (! x_mpq_integer_p (q->m))
657: goto integer_error;
658: if (! mpz_fits_slong_p (mpq_numref (q->m)))
659: goto range_error;
660: return mpz_get_si (mpq_numref (q->m));
661: }
662: if (sv_derived_from (sv, mpf_class))
663: {
664: mpf f = SvMPF(sv);
665: if (! mpf_integer_p (f))
666: goto integer_error;
667: if (! mpf_fits_slong_p (f))
668: goto range_error;
669: return mpf_get_si (f);
670: }
671: }
672: croak ("cannot coerce to long");
673: }
674:
675:
676: #define mpx_set_maybe(dst,src,type) \
677: do { if ((dst) != (src)) type##_set (dst, src); } while (0)
678:
679: #define coerce_mpx_into(p,sv,type) \
680: do { \
681: type##_ptr __new_p = coerce_##type (p, sv); \
682: mpx_set_maybe (p, __new_p, type); \
683: } while (0)
684:
685: /* Like plain coerce_mpz or coerce_mpq, but force the result into p by
686: copying if necessary. */
687: #define coerce_mpz_into(z,sv) coerce_mpx_into(z,sv,mpz)
688: #define coerce_mpq_into(q,sv) coerce_mpx_into(q,sv,mpq)
689:
690:
691: /* Prepare sv to be a changable mpz. If it's not an mpz then turn it into
692: one. If it is an mpz then ensure the reference count is 1. */
693: static mpz_ptr
694: mutate_mpz (SV *sv)
695: {
696: mpz old_z, new_z;
697:
698: TRACE (printf ("mutate_mpz %p\n", sv));
699: TRACE (printf (" type %d\n", SvTYPE(sv)));
700:
701: if (SvROK (sv) && sv_derived_from (sv, mpz_class))
702: {
703: old_z = SvMPZ(sv);
704: if (SvREFCNT(SvRV(sv)) == 1)
705: return SvMPZ(sv)->m;
706:
707: TRACE (printf ("mutate_mpz(): forking new mpz\n"));
708: new_z = new_mpz ();
709: mpz_set (new_z->m, old_z->m);
710: }
711: else
712: {
713: TRACE (printf ("mutate_mpz(): coercing new mpz\n"));
714: new_z = new_mpz ();
715: coerce_mpz_into (new_z->m, sv);
716: }
717: sv_setref_pv (sv, mpz_class, new_z);
718: return new_z->m;
719: }
720:
721:
722: /* ------------------------------------------------------------------------- */
723:
724: MODULE = GMP PACKAGE = GMP
725:
726: BOOT:
727: TRACE (printf ("GMP boot\n"));
728: mp_set_memory_functions (my_gmp_alloc, my_gmp_realloc, my_gmp_free);
729: mpz_init (tmp_mpz_0);
730: mpz_init (tmp_mpz_1);
731: mpz_init (tmp_mpz_2);
732: mpq_init (tmp_mpq_0);
733: mpq_init (tmp_mpq_1);
734: tmp_mpf_init (tmp_mpf_0);
735: tmp_mpf_init (tmp_mpf_1);
736:
737:
738: void
739: END()
740: CODE:
741: TRACE (printf ("GMP end\n"));
742: TRACE_ACTIVE ();
743: /* These are not always true, see Bugs at the top of the file. */
744: /* assert (mpz_count == 0); */
745: /* assert (mpq_count == 0); */
746: /* assert (mpf_count == 0); */
747: /* assert (rand_count == 0); */
748:
749:
750: const_string
751: version()
752: CODE:
753: RETVAL = gmp_version;
754: OUTPUT:
755: RETVAL
756:
757:
758: bool
759: fits_slong_p (sv)
760: SV *sv
761: PREINIT:
762: mpq_srcptr q;
763: CODE:
764: if (SvIOK(sv))
765: RETVAL = 1;
766: else if (SvNOK(sv))
767: {
768: double d = SvNVX(sv);
769: RETVAL = (d >= LONG_MIN && d <= LONG_MAX);
770: }
771: else if (SvPOKorp(sv))
772: {
773: STRLEN len;
774: const char *str = SvPV (sv, len);
775: if (mpq_set_str (tmp_mpq_0, str, 0) == 0)
776: RETVAL = x_mpq_fits_slong_p (tmp_mpq_0);
777: else
778: {
779: /* enough precision for a long */
780: tmp_mpf_set_prec (tmp_mpf_0, 2*mp_bits_per_limb);
781: if (mpf_set_str (tmp_mpf_0->m, str, 10) != 0)
782: croak ("GMP::fits_slong_p invalid string format");
783: RETVAL = mpf_fits_slong_p (tmp_mpf_0->m);
784: }
785: }
786: else if (SvROK(sv))
787: {
788: if (sv_derived_from (sv, mpz_class))
789: RETVAL = mpz_fits_slong_p (SvMPZ(sv)->m);
790: else if (sv_derived_from (sv, mpq_class))
791: RETVAL = x_mpq_fits_slong_p (SvMPQ(sv)->m);
792: else if (sv_derived_from (sv, mpf_class))
793: RETVAL = mpf_fits_slong_p (SvMPF(sv));
794: else
795: goto invalid;
796: }
797: else
798: {
799: invalid:
800: croak ("GMP::fits_slong_p invalid argument");
801: }
802: OUTPUT:
803: RETVAL
804:
805:
806: double
807: get_d (sv)
808: SV *sv
809: CODE:
810: if (SvIOK(sv))
811: RETVAL = (double) SvIVX(sv);
812: else if (SvNOK(sv))
813: RETVAL = SvNVX(sv);
814: else if (SvPOKorp(sv))
815: {
816: STRLEN len;
817: RETVAL = atof(SvPV(sv, len));
818: }
819: else if (SvROK(sv))
820: {
821: if (sv_derived_from (sv, mpz_class))
822: RETVAL = mpz_get_d (SvMPZ(sv)->m);
823: else if (sv_derived_from (sv, mpq_class))
824: RETVAL = mpq_get_d (SvMPQ(sv)->m);
825: else if (sv_derived_from (sv, mpf_class))
826: RETVAL = mpf_get_d (SvMPF(sv));
827: else
828: goto invalid;
829: }
830: else
831: {
832: invalid:
833: croak ("GMP::get_d invalid argument");
834: }
835: OUTPUT:
836: RETVAL
837:
838:
839: long
840: get_si (sv)
841: SV *sv
842: CODE:
843: if (SvIOK(sv))
844: RETVAL = SvIVX(sv);
845: else if (SvNOK(sv))
846: RETVAL = (long) SvNVX(sv);
847: else if (SvPOKorp(sv))
848: RETVAL = SvIV(sv);
849: else if (SvROK(sv))
850: {
851: if (sv_derived_from (sv, mpz_class))
852: RETVAL = mpz_get_si (SvMPZ(sv)->m);
853: else if (sv_derived_from (sv, mpq_class))
854: {
855: mpz_set_q (tmp_mpz_0, SvMPQ(sv)->m);
856: RETVAL = mpz_get_si (tmp_mpz_0);
857: }
858: else if (sv_derived_from (sv, mpf_class))
859: RETVAL = mpf_get_si (SvMPF(sv));
860: else
861: goto invalid;
862: }
863: else
864: {
865: invalid:
866: croak ("GMP::get_si invalid argument");
867: }
868: OUTPUT:
869: RETVAL
870:
871:
872: void
873: get_str (sv, ...)
874: SV *sv
875: PREINIT:
876: char *str;
877: mp_exp_t exp;
878: mpz_ptr z;
879: mpq_ptr q;
880: mpf f;
881: int base;
882: int ndigits;
883: PPCODE:
884: TRACE (printf ("GMP::get_str\n"));
885:
886: if (items >= 2)
887: base = coerce_long (ST(1));
888: else
889: base = 10;
890: TRACE (printf (" base=%d\n", base));
891:
892: if (items >= 3)
893: ndigits = coerce_long (ST(2));
894: else
895: ndigits = 10;
896: TRACE (printf (" ndigits=%d\n", ndigits));
897:
898: EXTEND (SP, 2);
899:
900: if (SvIOK(sv))
901: {
902: mpz_set_si (tmp_mpz_0, SvIVX(sv));
903: z = tmp_mpz_0;
904: goto get_mpz;
905: }
906: else if (SvNOK(sv))
907: {
908: /* only digits in the original double, not in the coerced form */
909: if (ndigits == 0)
910: ndigits = DBL_DIG;
911: mpf_set_d (tmp_mpf_0->m, SvNVX(sv));
912: f = tmp_mpf_0->m;
913: goto get_mpf;
914: }
915: else if (SvPOKorp(sv))
916: {
917: /* get_str on a string is not much more than a base conversion */
918: STRLEN len;
919: str = SvPV (sv, len);
920: if (mpz_set_str (tmp_mpz_0, str, 0) == 0)
921: {
922: z = tmp_mpz_0;
923: goto get_mpz;
924: }
925: else if (mpq_set_str (tmp_mpq_0, str, 0) == 0)
926: {
927: q = tmp_mpq_0;
928: goto get_mpq;
929: }
930: else
931: {
932: /* FIXME: Would like perhaps a precision equivalent to the
933: number of significant digits of the string, in its given
934: base. */
935: tmp_mpf_set_prec (tmp_mpf_0, strlen(str));
936: if (mpf_set_str (tmp_mpf_0->m, str, 10) == 0)
937: {
938: f = tmp_mpf_0->m;
939: goto get_mpf;
940: }
941: else
942: croak ("GMP::get_str invalid string format");
943: }
944: }
945: else if (SvROK(sv))
946: {
947: if (sv_derived_from (sv, mpz_class))
948: {
949: z = SvMPZ(sv)->m;
950: get_mpz:
951: str = mpz_get_str (NULL, base, z);
952: push_str:
953: PUSHs (sv_2mortal (newSVpv (str, 0)));
954: }
955: else if (sv_derived_from (sv, mpq_class))
956: {
957: q = SvMPQ(sv)->m;
958: get_mpq:
959: str = mpq_get_str (NULL, base, q);
960: goto push_str;
961: }
962: else if (sv_derived_from (sv, mpf_class))
963: {
964: f = SvMPF(sv);
965: get_mpf:
966: str = mpf_get_str (NULL, &exp, base, 0, f);
967: PUSHs (sv_2mortal (newSVpv (str, 0)));
968: PUSHs (sv_2mortal (newSViv (exp)));
969: }
970: else
971: goto invalid;
972: }
973: else
974: {
975: invalid:
976: croak ("GMP::get_str invalid argument");
977: }
978:
979:
980: bool
981: integer_p (sv)
982: SV *sv
983: CODE:
984: if (SvIOK(sv))
985: RETVAL = 1;
986: else if (SvNOK(sv))
987: RETVAL = double_integer_p (SvNVX(sv));
988: else if (SvPOKorp(sv))
989: {
990: /* FIXME: Maybe this should be done by parsing the string, not by an
991: actual conversion. */
992: STRLEN len;
993: const char *str = SvPV (sv, len);
994: if (mpq_set_str (tmp_mpq_0, str, 0) == 0)
995: RETVAL = x_mpq_integer_p (tmp_mpq_0);
996: else
997: {
998: /* enough for all digits of the string */
999: tmp_mpf_set_prec (tmp_mpf_0, strlen(str)+64);
1000: if (mpf_set_str (tmp_mpf_0->m, str, 10) == 0)
1001: RETVAL = mpf_integer_p (tmp_mpf_0->m);
1002: else
1003: croak ("GMP::integer_p invalid string format");
1004: }
1005: }
1006: else if (SvROK(sv))
1007: {
1008: if (sv_derived_from (sv, mpz_class))
1009: RETVAL = 1;
1010: else if (sv_derived_from (sv, mpq_class))
1011: RETVAL = x_mpq_integer_p (SvMPQ(sv)->m);
1012: else if (sv_derived_from (sv, mpf_class))
1013: RETVAL = mpf_integer_p (SvMPF(sv));
1014: else
1015: goto invalid;
1016: }
1017: else
1018: {
1019: invalid:
1020: croak ("GMP::integer_p invalid argument");
1021: }
1022: OUTPUT:
1023: RETVAL
1024:
1025:
1026: int
1027: sgn (sv)
1028: SV *sv
1029: CODE:
1030: if (SvIOK(sv))
1031: RETVAL = SGN (SvIVX(sv));
1032: else if (SvNOK(sv))
1033: RETVAL = SGN (SvNVX(sv));
1034: else if (SvPOKorp(sv))
1035: {
1036: /* FIXME: Maybe this should be done by parsing the string, not by an
1037: actual conversion. */
1038: STRLEN len;
1039: const char *str = SvPV (sv, len);
1040: if (mpq_set_str (tmp_mpq_0, str, 0) == 0)
1041: RETVAL = mpq_sgn (tmp_mpq_0);
1042: else
1043: {
1044: /* enough for all digits of the string */
1045: tmp_mpf_set_prec (tmp_mpf_0, strlen(str)+64);
1046: if (mpf_set_str (tmp_mpf_0->m, str, 10) == 0)
1047: RETVAL = mpf_sgn (tmp_mpf_0->m);
1048: else
1049: croak ("GMP::sgn invalid string format");
1050: }
1051: }
1052: else if (SvROK(sv))
1053: {
1054: if (sv_derived_from (sv, mpz_class))
1055: RETVAL = mpz_sgn (SvMPZ(sv)->m);
1056: else if (sv_derived_from (sv, mpq_class))
1057: RETVAL = mpq_sgn (SvMPQ(sv)->m);
1058: else if (sv_derived_from (sv, mpf_class))
1059: RETVAL = mpf_sgn (SvMPF(sv));
1060: else
1061: goto invalid;
1062: }
1063: else
1064: {
1065: invalid:
1066: croak ("GMP::sgn invalid argument");
1067: }
1068: OUTPUT:
1069: RETVAL
1070:
1071:
1072: # currently undocumented
1073: void
1074: shrink ()
1075: CODE:
1076: #define x_mpz_shrink(z) \
1077: mpz_set_ui (z, 0L); _mpz_realloc (z, 1)
1078: #define x_mpq_shrink(q) \
1079: x_mpz_shrink (mpq_numref(q)); x_mpz_shrink (mpq_denref(q))
1080:
1081: x_mpz_shrink (tmp_mpz_0);
1082: x_mpz_shrink (tmp_mpz_1);
1083: x_mpz_shrink (tmp_mpz_2);
1084: x_mpq_shrink (tmp_mpq_0);
1085: x_mpq_shrink (tmp_mpq_1);
1086: tmp_mpf_shrink (tmp_mpf_0);
1087: tmp_mpf_shrink (tmp_mpf_1);
1088:
1089:
1090:
1091: malloced_string
1092: sprintf_internal (fmt, sv)
1093: const_string fmt
1094: SV *sv
1095: CODE:
1096: assert (strlen (fmt) >= 3);
1097: assert (SvROK(sv));
1098: assert ((sv_derived_from (sv, mpz_class) && fmt[strlen(fmt)-2] == 'Z')
1099: || (sv_derived_from (sv, mpq_class) && fmt[strlen(fmt)-2] == 'Q')
1100: || (sv_derived_from (sv, mpf_class) && fmt[strlen(fmt)-2] == 'F'));
1101: TRACE (printf ("GMP::sprintf_internal\n");
1102: printf (" fmt |%s|\n", fmt);
1103: printf (" sv |%p|\n", SvMPZ(sv)));
1104:
1105: /* cheat a bit here, SvMPZ works for mpq and mpf too */
1106: gmp_asprintf (&RETVAL, fmt, SvMPZ(sv));
1107:
1108: TRACE (printf (" result |%s|\n", RETVAL));
1109: OUTPUT:
1110: RETVAL
1111:
1112:
1113:
1114: #------------------------------------------------------------------------------
1115:
1116: MODULE = GMP PACKAGE = GMP::Mpz
1117:
1118: mpz
1119: mpz (...)
1120: ALIAS:
1121: GMP::Mpz::new = 1
1122: PREINIT:
1123: SV *sv;
1124: CODE:
1125: TRACE (printf ("%s new, ix=%ld, items=%d\n", mpz_class, ix, items));
1126: RETVAL = new_mpz();
1127:
1128: switch (items) {
1129: case 0:
1130: mpz_set_ui (RETVAL->m, 0L);
1131: break;
1132: case 1:
1133: sv = ST(0);
1134: if (SvIOK(sv)) mpz_set_si (RETVAL->m, SvIVX(sv));
1135: else if (SvNOK(sv)) mpz_set_d (RETVAL->m, SvNVX(sv));
1136: else if (SvPOKorp(sv)) my_mpz_set_svstr (RETVAL->m, sv);
1137: else if (SvROK(sv))
1138: {
1139: if (sv_derived_from (sv, mpz_class))
1140: mpz_set (RETVAL->m, SvMPZ(sv)->m);
1141: else if (sv_derived_from (sv, mpq_class))
1142: mpz_set_q (RETVAL->m, SvMPQ(sv)->m);
1143: else if (sv_derived_from (sv, mpf_class))
1144: mpz_set_f (RETVAL->m, SvMPF(sv));
1145: else
1146: goto invalid;
1147: }
1148: else
1149: goto invalid;
1150: break;
1151: default:
1152: invalid:
1153: croak ("%s new: invalid arguments", mpz_class);
1154: }
1155: OUTPUT:
1156: RETVAL
1157:
1158:
1159: void
1160: overload_constant (str, pv, d1, ...)
1161: const_string_assume str
1162: SV *pv
1163: dummy d1
1164: PREINIT:
1165: mpz z;
1166: PPCODE:
1167: TRACE (printf ("%s constant: %s\n", mpz_class, str));
1168: z = new_mpz();
1169: if (mpz_set_str (z->m, str, 0) == 0)
1170: {
1171: SV *sv = sv_newmortal(); sv_setref_pv (sv, mpz_class, z); PUSHs(sv);
1172: }
1173: else
1174: {
1175: free_mpz (z);
1176: PUSHs(pv);
1177: }
1178:
1179:
1180: mpz
1181: overload_copy (z, d1, d2)
1182: mpz_assume z
1183: dummy d1
1184: dummy d2
1185: CODE:
1186: RETVAL = new_mpz();
1187: mpz_set (RETVAL->m, z->m);
1188: OUTPUT:
1189: RETVAL
1190:
1191:
1192: void
1193: DESTROY (z)
1194: mpz_assume z
1195: CODE:
1196: TRACE (printf ("%s DESTROY %p\n", mpz_class, z));
1197: free_mpz (z);
1198:
1199:
1200: malloced_string
1201: overload_string (z, d1, d2)
1202: mpz_assume z
1203: dummy d1
1204: dummy d2
1205: CODE:
1206: TRACE (printf ("%s overload_string %p\n", mpz_class, z));
1207: RETVAL = mpz_get_str (NULL, 10, z->m);
1208: OUTPUT:
1209: RETVAL
1210:
1211:
1212: mpz
1213: overload_add (xv, yv, order)
1214: SV *xv
1215: SV *yv
1216: SV *order
1217: ALIAS:
1218: GMP::Mpz::overload_sub = 1
1219: GMP::Mpz::overload_mul = 2
1220: GMP::Mpz::overload_div = 3
1221: GMP::Mpz::overload_rem = 4
1222: GMP::Mpz::overload_and = 5
1223: GMP::Mpz::overload_ior = 6
1224: GMP::Mpz::overload_xor = 7
1225: PREINIT:
1226: static const struct {
1227: void (*op) (mpz_ptr, mpz_srcptr, mpz_srcptr);
1228: } table[] = {
1229: { mpz_add }, /* 0 */
1230: { mpz_sub }, /* 1 */
1231: { mpz_mul }, /* 2 */
1232: { mpz_tdiv_q }, /* 3 */
1233: { mpz_tdiv_r }, /* 4 */
1234: { mpz_and }, /* 5 */
1235: { mpz_ior }, /* 6 */
1236: { mpz_xor }, /* 7 */
1237: };
1238: CODE:
1239: assert_table (ix);
1240: if (order == &PL_sv_yes)
1241: SV_PTR_SWAP (xv, yv);
1242: RETVAL = new_mpz();
1243: (*table[ix].op) (RETVAL->m,
1244: coerce_mpz (tmp_mpz_0, xv),
1245: coerce_mpz (tmp_mpz_1, yv));
1246: OUTPUT:
1247: RETVAL
1248:
1249:
1250: void
1251: overload_addeq (x, y, o)
1252: mpz_assume x
1253: mpz_coerce y
1254: order_noswap o
1255: ALIAS:
1256: GMP::Mpz::overload_subeq = 1
1257: GMP::Mpz::overload_muleq = 2
1258: GMP::Mpz::overload_diveq = 3
1259: GMP::Mpz::overload_remeq = 4
1260: GMP::Mpz::overload_andeq = 5
1261: GMP::Mpz::overload_ioreq = 6
1262: GMP::Mpz::overload_xoreq = 7
1263: PREINIT:
1264: static const struct {
1265: void (*op) (mpz_ptr, mpz_srcptr, mpz_srcptr);
1266: } table[] = {
1267: { mpz_add }, /* 0 */
1268: { mpz_sub }, /* 1 */
1269: { mpz_mul }, /* 2 */
1270: { mpz_tdiv_q }, /* 3 */
1271: { mpz_tdiv_r }, /* 4 */
1272: { mpz_and }, /* 5 */
1273: { mpz_ior }, /* 6 */
1274: { mpz_xor }, /* 7 */
1275: };
1276: PPCODE:
1277: assert_table (ix);
1278: (*table[ix].op) (x->m, x->m, y);
1279: XPUSHs (ST(0));
1280:
1281:
1282: mpz
1283: overload_lshift (zv, nv, order)
1284: SV *zv
1285: SV *nv
1286: SV *order
1287: ALIAS:
1288: GMP::Mpz::overload_rshift = 1
1289: GMP::Mpz::overload_pow = 2
1290: PREINIT:
1291: static const struct {
1292: void (*op) (mpz_ptr, mpz_srcptr, unsigned long);
1293: } table[] = {
1294: { mpz_mul_2exp }, /* 0 */
1295: { mpz_div_2exp }, /* 1 */
1296: { mpz_pow_ui }, /* 2 */
1297: };
1298: CODE:
1299: assert_table (ix);
1300: if (order == &PL_sv_yes)
1301: SV_PTR_SWAP (zv, nv);
1302: RETVAL = new_mpz();
1303: (*table[ix].op) (RETVAL->m, coerce_mpz (RETVAL->m, zv), coerce_ulong (nv));
1304: OUTPUT:
1305: RETVAL
1306:
1307:
1308: void
1309: overload_lshifteq (z, n, o)
1310: mpz_assume z
1311: ulong_coerce n
1312: order_noswap o
1313: ALIAS:
1314: GMP::Mpz::overload_rshifteq = 1
1315: GMP::Mpz::overload_poweq = 2
1316: PREINIT:
1317: static const struct {
1318: void (*op) (mpz_ptr, mpz_srcptr, unsigned long);
1319: } table[] = {
1320: { mpz_mul_2exp }, /* 0 */
1321: { mpz_div_2exp }, /* 1 */
1322: { mpz_pow_ui }, /* 2 */
1323: };
1324: PPCODE:
1325: assert_table (ix);
1326: (*table[ix].op) (z->m, z->m, n);
1327: XPUSHs(ST(0));
1328:
1329:
1330: mpz
1331: overload_abs (z, d1, d2)
1332: mpz_assume z
1333: dummy d1
1334: dummy d2
1335: ALIAS:
1336: GMP::Mpz::overload_neg = 1
1337: GMP::Mpz::overload_com = 2
1338: GMP::Mpz::overload_sqrt = 3
1339: PREINIT:
1340: static const struct {
1341: void (*op) (mpz_ptr w, mpz_srcptr x);
1342: } table[] = {
1343: { mpz_abs }, /* 0 */
1344: { mpz_neg }, /* 1 */
1345: { mpz_com }, /* 2 */
1346: { mpz_sqrt }, /* 3 */
1347: };
1348: CODE:
1349: assert_table (ix);
1350: RETVAL = new_mpz();
1351: (*table[ix].op) (RETVAL->m, z->m);
1352: OUTPUT:
1353: RETVAL
1354:
1355:
1356: void
1357: overload_inc (z, d1, d2)
1358: mpz_assume z
1359: dummy d1
1360: dummy d2
1361: ALIAS:
1362: GMP::Mpz::overload_dec = 1
1363: PREINIT:
1364: static const struct {
1365: void (*op) (mpz_ptr w, mpz_srcptr x, unsigned long y);
1366: } table[] = {
1367: { mpz_add_ui }, /* 0 */
1368: { mpz_sub_ui }, /* 1 */
1369: };
1370: CODE:
1371: assert_table (ix);
1372: (*table[ix].op) (z->m, z->m, 1L);
1373:
1374:
1375: int
1376: overload_spaceship (xv, yv, order)
1377: SV *xv
1378: SV *yv
1379: SV *order
1380: PREINIT:
1381: mpz x;
1382: CODE:
1383: TRACE (printf ("%s overload_spaceship\n", mpz_class));
1384: MPZ_ASSUME (x, xv);
1385: if (SvIOK(yv))
1386: RETVAL = mpz_cmp_si (x->m, SvIVX(yv));
1387: else if (SvPOKorp(yv))
1388: RETVAL = mpz_cmp (x->m, coerce_mpz (tmp_mpz_0, yv));
1389: else if (SvNOK(yv))
1390: RETVAL = mpz_cmp_d (x->m, SvNVX(yv));
1391: else if (SvROK(yv))
1392: {
1393: if (sv_derived_from (yv, mpz_class))
1394: RETVAL = mpz_cmp (x->m, SvMPZ(yv)->m);
1395: else if (sv_derived_from (yv, mpq_class))
1396: RETVAL = x_mpz_cmp_q (x->m, SvMPQ(yv)->m);
1397: else if (sv_derived_from (yv, mpf_class))
1398: RETVAL = x_mpz_cmp_f (x->m, SvMPF(yv));
1399: else
1400: goto invalid;
1401: }
1402: else
1403: {
1404: invalid:
1405: croak ("%s <=>: invalid operand", mpz_class);
1406: }
1407: RETVAL = SGN (RETVAL);
1408: if (order == &PL_sv_yes)
1409: RETVAL = -RETVAL;
1410: OUTPUT:
1411: RETVAL
1412:
1413:
1414: bool
1415: overload_bool (z, d1, d2)
1416: mpz_assume z
1417: dummy d1
1418: dummy d2
1419: ALIAS:
1420: GMP::Mpz::overload_not = 1
1421: CODE:
1422: RETVAL = (mpz_sgn (z->m) != 0) ^ ix;
1423: OUTPUT:
1424: RETVAL
1425:
1426:
1427: mpz
1428: bin (n, k)
1429: mpz_coerce n
1430: ulong_coerce k
1431: ALIAS:
1432: GMP::Mpz::root = 1
1433: PREINIT:
1434: /* mpz_root returns an int, hence the cast */
1435: static const struct {
1436: void (*op) (mpz_ptr, mpz_srcptr, unsigned long);
1437: } table[] = {
1438: { mpz_bin_ui }, /* 0 */
1439: { (void (*)(mpz_ptr, mpz_srcptr, unsigned long)) mpz_root }, /* 1 */
1440: };
1441: CODE:
1442: assert_table (ix);
1443: RETVAL = new_mpz();
1444: (*table[ix].op) (RETVAL->m, n, k);
1445: OUTPUT:
1446: RETVAL
1447:
1448:
1449: void
1450: cdiv (a, d)
1451: mpz_coerce a
1452: mpz_coerce d
1453: ALIAS:
1454: GMP::Mpz::fdiv = 1
1455: GMP::Mpz::tdiv = 2
1456: PREINIT:
1457: static const struct {
1458: void (*op) (mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr);
1459: } table[] = {
1460: { mpz_cdiv_qr }, /* 0 */
1461: { mpz_fdiv_qr }, /* 1 */
1462: { mpz_tdiv_qr }, /* 2 */
1463: };
1464: mpz q, r;
1465: SV *sv;
1466: PPCODE:
1467: assert_table (ix);
1468: q = new_mpz();
1469: r = new_mpz();
1470: (*table[ix].op) (q->m, r->m, a, d);
1471: EXTEND (SP, 2);
1472: sv = sv_newmortal(); sv_setref_pv (sv, mpz_class, q); PUSHs(sv);
1473: sv = sv_newmortal(); sv_setref_pv (sv, mpz_class, r); PUSHs(sv);
1474:
1475:
1476: void
1477: cdiv_2exp (a, d)
1478: mpz_coerce a
1479: ulong_coerce d
1480: ALIAS:
1481: GMP::Mpz::fdiv_2exp = 1
1482: GMP::Mpz::tdiv_2exp = 2
1483: PREINIT:
1484: static const struct {
1485: void (*q) (mpz_ptr, mpz_srcptr, unsigned long);
1486: void (*r) (mpz_ptr, mpz_srcptr, unsigned long);
1487: } table[] = {
1488: { mpz_cdiv_q_2exp, mpz_cdiv_r_2exp }, /* 0 */
1489: { mpz_fdiv_q_2exp, mpz_fdiv_r_2exp }, /* 1 */
1490: { mpz_tdiv_q_2exp, mpz_tdiv_r_2exp }, /* 2 */
1491: };
1492: mpz q, r;
1493: SV *sv;
1494: PPCODE:
1495: assert_table (ix);
1496: q = new_mpz();
1497: r = new_mpz();
1498: (*table[ix].q) (q->m, a, d);
1499: (*table[ix].r) (r->m, a, d);
1500: EXTEND (SP, 2);
1501: sv = sv_newmortal(); sv_setref_pv (sv, mpz_class, q); PUSHs(sv);
1502: sv = sv_newmortal(); sv_setref_pv (sv, mpz_class, r); PUSHs(sv);
1503:
1504:
1505: bool
1506: congruent_p (a, c, d)
1507: mpz_coerce a
1508: mpz_coerce c
1509: mpz_coerce d
1510: PREINIT:
1511: CODE:
1512: RETVAL = mpz_congruent_p (a, c, d);
1513: OUTPUT:
1514: RETVAL
1515:
1516:
1517: bool
1518: congruent_2exp_p (a, c, d)
1519: mpz_coerce a
1520: mpz_coerce c
1521: ulong_coerce d
1522: PREINIT:
1523: CODE:
1524: RETVAL = mpz_congruent_2exp_p (a, c, d);
1525: OUTPUT:
1526: RETVAL
1527:
1528:
1529: mpz
1530: divexact (a, d)
1531: mpz_coerce a
1532: mpz_coerce d
1533: ALIAS:
1534: GMP::Mpz::mod = 1
1535: PREINIT:
1536: static const struct {
1537: void (*op) (mpz_ptr, mpz_srcptr, mpz_srcptr);
1538: } table[] = {
1539: { mpz_divexact }, /* 0 */
1540: { mpz_mod }, /* 1 */
1541: };
1542: CODE:
1543: assert_table (ix);
1544: RETVAL = new_mpz();
1545: (*table[ix].op) (RETVAL->m, a, d);
1546: OUTPUT:
1547: RETVAL
1548:
1549:
1550: bool
1551: divisible_p (a, d)
1552: mpz_coerce a
1553: mpz_coerce d
1554: CODE:
1555: RETVAL = mpz_divisible_p (a, d);
1556: OUTPUT:
1557: RETVAL
1558:
1559:
1560: bool
1561: divisible_2exp_p (a, d)
1562: mpz_coerce a
1563: ulong_coerce d
1564: CODE:
1565: RETVAL = mpz_divisible_2exp_p (a, d);
1566: OUTPUT:
1567: RETVAL
1568:
1569:
1570: bool
1571: even_p (z)
1572: mpz_coerce z
1573: ALIAS:
1574: GMP::Mpz::odd_p = 1
1575: GMP::Mpz::perfect_square_p = 2
1576: GMP::Mpz::perfect_power_p = 3
1577: PREINIT:
1578: static const struct {
1579: int (*op) (mpz_srcptr z);
1580: } table[] = {
1581: { x_mpz_even_p }, /* 0 */
1582: { x_mpz_odd_p }, /* 1 */
1583: { mpz_perfect_square_p }, /* 2 */
1584: { mpz_perfect_power_p }, /* 3 */
1585: };
1586: CODE:
1587: assert_table (ix);
1588: RETVAL = (*table[ix].op) (z);
1589: OUTPUT:
1590: RETVAL
1591:
1592:
1593: mpz
1594: fac (n)
1595: ulong_coerce n
1596: ALIAS:
1597: GMP::Mpz::fib = 1
1598: GMP::Mpz::lucnum = 2
1599: PREINIT:
1600: static const struct {
1601: void (*op) (mpz_ptr r, unsigned long n);
1602: } table[] = {
1603: { mpz_fac_ui }, /* 0 */
1604: { mpz_fib_ui }, /* 1 */
1605: { mpz_lucnum_ui }, /* 2 */
1606: };
1607: CODE:
1608: assert_table (ix);
1609: RETVAL = new_mpz();
1610: (*table[ix].op) (RETVAL->m, n);
1611: OUTPUT:
1612: RETVAL
1613:
1614:
1615: void
1616: fib2 (n)
1617: ulong_coerce n
1618: ALIAS:
1619: GMP::Mpz::lucnum2 = 1
1620: PREINIT:
1621: static const struct {
1622: void (*op) (mpz_ptr r, mpz_ptr r2, unsigned long n);
1623: } table[] = {
1624: { mpz_fib2_ui }, /* 0 */
1625: { mpz_lucnum2_ui }, /* 1 */
1626: };
1627: mpz r, r2;
1628: SV *sv;
1629: PPCODE:
1630: assert_table (ix);
1631: r = new_mpz();
1632: r2 = new_mpz();
1633: (*table[ix].op) (r->m, r2->m, n);
1634: EXTEND (SP, 2);
1635: sv = sv_newmortal(); sv_setref_pv (sv, mpz_class, r); PUSHs(sv);
1636: sv = sv_newmortal(); sv_setref_pv (sv, mpz_class, r2); PUSHs(sv);
1637:
1638:
1639: mpz
1640: gcd (x, ...)
1641: mpz_coerce x
1642: ALIAS:
1643: GMP::Mpz::lcm = 1
1644: PREINIT:
1645: static const struct {
1646: void (*op) (mpz_ptr w, mpz_srcptr x, mpz_srcptr y);
1647: void (*op_ui) (mpz_ptr w, mpz_srcptr x, unsigned long y);
1648: } table[] = {
1649: /* cast to ignore ulong return from mpz_gcd_ui */
1650: { mpz_gcd,
1651: (void (*) (mpz_ptr, mpz_srcptr, unsigned long)) mpz_gcd_ui }, /* 0 */
1652: { mpz_lcm, mpz_lcm_ui }, /* 1 */
1653: };
1654: int i;
1655: SV *yv;
1656: CODE:
1657: assert_table (ix);
1658: RETVAL = new_mpz();
1659: if (items == 1)
1660: mpz_set (RETVAL->m, x);
1661: else
1662: {
1663: for (i = 1; i < items; i++)
1664: {
1665: yv = ST(i);
1666: if (SvIOK(yv))
1667: (*table[ix].op_ui) (RETVAL->m, x, ABS(SvIVX(yv)));
1668: else
1669: (*table[ix].op) (RETVAL->m, x, coerce_mpz (tmp_mpz_1, yv));
1670: x = RETVAL->m;
1671: }
1672: }
1673: OUTPUT:
1674: RETVAL
1675:
1676:
1677: void
1678: gcdext (a, b)
1679: mpz_coerce a
1680: mpz_coerce b
1681: PREINIT:
1682: mpz g, x, y;
1683: SV *sv;
1684: PPCODE:
1685: g = new_mpz();
1686: x = new_mpz();
1687: y = new_mpz();
1688: mpz_gcdext (g->m, x->m, y->m, a, b);
1689: EXTEND (SP, 3);
1690: sv = sv_newmortal(); sv_setref_pv (sv, mpz_class, g); PUSHs(sv);
1691: sv = sv_newmortal(); sv_setref_pv (sv, mpz_class, x); PUSHs(sv);
1692: sv = sv_newmortal(); sv_setref_pv (sv, mpz_class, y); PUSHs(sv);
1693:
1694:
1695: unsigned long
1696: hamdist (x, y)
1697: mpz_coerce x
1698: mpz_coerce y
1699: CODE:
1700: RETVAL = mpz_hamdist (x, y);
1701: OUTPUT:
1702: RETVAL
1703:
1704:
1705: mpz
1706: invert (a, m)
1707: mpz_coerce a
1708: mpz_coerce m
1709: CODE:
1710: RETVAL = new_mpz();
1711: if (! mpz_invert (RETVAL->m, a, m))
1712: {
1713: free_mpz (RETVAL);
1714: XSRETURN_UNDEF;
1715: }
1716: OUTPUT:
1717: RETVAL
1718:
1719:
1720: int
1721: jacobi (a, b)
1722: mpz_coerce a
1723: mpz_coerce b
1724: CODE:
1725: RETVAL = mpz_jacobi (a, b);
1726: OUTPUT:
1727: RETVAL
1728:
1729:
1730: int
1731: kronecker (a, b)
1732: SV *a
1733: SV *b
1734: CODE:
1735: if (SvIOK(b))
1736: RETVAL = mpz_kronecker_si (coerce_mpz(tmp_mpz_0,a), SvIVX(b));
1737: else if (SvIOK(a))
1738: RETVAL = mpz_si_kronecker (SvIVX(a), coerce_mpz(tmp_mpz_0,b));
1739: else
1740: RETVAL = mpz_kronecker (coerce_mpz(tmp_mpz_0,a),
1741: coerce_mpz(tmp_mpz_1,b));
1742: OUTPUT:
1743: RETVAL
1744:
1745:
1746: mpz
1747: nextprime (z)
1748: mpz_coerce z
1749: CODE:
1750: RETVAL = new_mpz();
1751: mpz_nextprime (RETVAL->m, z);
1752: OUTPUT:
1753: RETVAL
1754:
1755:
1756: unsigned long
1757: popcount (x)
1758: mpz_coerce x
1759: CODE:
1760: RETVAL = mpz_popcount (x);
1761: OUTPUT:
1762: RETVAL
1763:
1764:
1765: mpz
1766: powm (b, e, m)
1767: mpz_coerce b
1768: mpz_coerce e
1769: mpz_coerce m
1770: CODE:
1771: RETVAL = new_mpz();
1772: mpz_powm (RETVAL->m, b, e, m);
1773: OUTPUT:
1774: RETVAL
1775:
1776:
1777: bool
1778: probab_prime_p (z, n)
1779: mpz_coerce z
1780: ulong_coerce n
1781: CODE:
1782: RETVAL = mpz_probab_prime_p (z, n);
1783: OUTPUT:
1784: RETVAL
1785:
1786:
1787: # No attempt to coerce here, only an mpz makes sense.
1788: void
1789: realloc (z, limbs)
1790: mpz z
1791: int limbs
1792: CODE:
1793: _mpz_realloc (z->m, limbs);
1794:
1795:
1796: void
1797: remove (z, f)
1798: mpz_coerce z
1799: mpz_coerce f
1800: PREINIT:
1801: SV *sv;
1802: mpz rem;
1803: unsigned long mult;
1804: dTARG;
1805: PPCODE:
1806: rem = new_mpz();
1807: mult = mpz_remove (rem->m, z, f);
1808: EXTEND (SP, 2);
1809: sv = sv_newmortal(); sv_setref_pv (sv, mpz_class, rem); PUSHs(sv);
1810: PUSHs (sv_2mortal (newSViv (mult)));
1811:
1812:
1813: void
1814: roote (z, n)
1815: mpz_coerce z
1816: ulong_coerce n
1817: PREINIT:
1818: SV *sv;
1819: mpz root;
1820: int exact;
1821: PPCODE:
1822: root = new_mpz();
1823: exact = mpz_root (root->m, z, n);
1824: EXTEND (SP, 2);
1825: sv = sv_newmortal(); sv_setref_pv (sv, mpz_class, root); PUSHs(sv);
1826: sv = (exact ? &PL_sv_yes : &PL_sv_no); sv_2mortal(sv); PUSHs(sv);
1827:
1828:
1829: unsigned long
1830: scan0 (z, start)
1831: mpz_coerce z
1832: ulong_coerce start
1833: ALIAS:
1834: GMP::Mpz::scan1 = 1
1835: PREINIT:
1836: static const struct {
1837: unsigned long (*op) (mpz_srcptr, unsigned long);
1838: } table[] = {
1839: { mpz_scan0 }, /* 0 */
1840: { mpz_scan1 }, /* 1 */
1841: };
1842: CODE:
1843: assert_table (ix);
1844: RETVAL = (*table[ix].op) (z, start);
1845: OUTPUT:
1846: RETVAL
1847:
1848:
1849: void
1850: setbit (z, bit)
1851: mpz_mutate z
1852: ulong_coerce bit
1853: ALIAS:
1854: GMP::Mpz::clrbit = 1
1855: PREINIT:
1856: static const struct {
1857: void (*op) (mpz_ptr, unsigned long);
1858: } table[] = {
1859: { mpz_setbit }, /* 0 */
1860: { mpz_clrbit }, /* 1 */
1861: };
1862: CODE:
1863: TRACE (printf ("%s %s\n", mpz_class, (ix==0 ? "setbit" : "clrbit")));
1864: assert (SvROK(ST(0)) && SvREFCNT(SvRV(ST(0))) == 1);
1865: assert_table (ix);
1866: (*table[ix].op) (z, bit);
1867:
1868:
1869: void
1870: sqrtrem (z)
1871: mpz_coerce z
1872: PREINIT:
1873: SV *sv;
1874: mpz root;
1875: mpz rem;
1876: PPCODE:
1877: root = new_mpz();
1878: rem = new_mpz();
1879: mpz_sqrtrem (root->m, rem->m, z);
1880: EXTEND (SP, 2);
1881: sv = sv_newmortal(); sv_setref_pv (sv, mpz_class, root); PUSHs(sv);
1882: sv = sv_newmortal(); sv_setref_pv (sv, mpz_class, rem); PUSHs(sv);
1883:
1884:
1885: size_t
1886: sizeinbase (z, base)
1887: mpz_coerce z
1888: int base
1889: CODE:
1890: RETVAL = mpz_sizeinbase (z, base);
1891: OUTPUT:
1892: RETVAL
1893:
1894:
1895: int
1896: tstbit (z, bit)
1897: mpz_coerce z
1898: ulong_coerce bit
1899: CODE:
1900: RETVAL = mpz_tstbit (z, bit);
1901: OUTPUT:
1902: RETVAL
1903:
1904:
1905:
1906: #------------------------------------------------------------------------------
1907:
1908: MODULE = GMP PACKAGE = GMP::Mpq
1909:
1910:
1911: mpq
1912: mpq (...)
1913: ALIAS:
1914: GMP::Mpq::new = 1
1915: PREINIT:
1916: CODE:
1917: TRACE (printf ("%s new\n", mpq_class));
1918: RETVAL = new_mpq();
1919:
1920: switch (items) {
1921: case 0:
1922: mpq_set_ui (RETVAL->m, 0L, 1L);
1923: break;
1924: case 1:
1925: coerce_mpq_into (RETVAL->m, ST(0));
1926: break;
1927: case 2:
1928: coerce_mpz_into (mpq_numref(RETVAL->m), ST(0));
1929: coerce_mpz_into (mpq_denref(RETVAL->m), ST(1));
1930: break;
1931: default:
1932: croak ("%s new: invalid arguments", mpq_class);
1933: }
1934: OUTPUT:
1935: RETVAL
1936:
1937:
1938: void
1939: overload_constant (str, pv, d1, ...)
1940: const_string_assume str
1941: SV *pv
1942: dummy d1
1943: PREINIT:
1944: SV *sv;
1945: mpq q;
1946: PPCODE:
1947: TRACE (printf ("%s constant: %s\n", mpq_class, str));
1948: q = new_mpq();
1949: if (mpq_set_str (q->m, str, 0) == 0)
1950: { sv = sv_newmortal(); sv_setref_pv (sv, mpq_class, q); }
1951: else
1952: { free_mpq (q); sv = pv; }
1953: XPUSHs(sv);
1954:
1955:
1956: mpq
1957: overload_copy (q, d1, d2)
1958: mpq_assume q
1959: dummy d1
1960: dummy d2
1961: CODE:
1962: RETVAL = new_mpq();
1963: mpq_set (RETVAL->m, q->m);
1964: OUTPUT:
1965: RETVAL
1966:
1967:
1968: void
1969: DESTROY (q)
1970: mpq_assume q
1971: CODE:
1972: TRACE (printf ("%s DESTROY %p\n", mpq_class, q));
1973: free_mpq (q);
1974:
1975:
1976: malloced_string
1977: overload_string (q, d1, d2)
1978: mpq_assume q
1979: dummy d1
1980: dummy d2
1981: CODE:
1982: TRACE (printf ("%s overload_string %p\n", mpq_class, q));
1983: RETVAL = mpq_get_str (NULL, 10, q->m);
1984: OUTPUT:
1985: RETVAL
1986:
1987:
1988: mpq
1989: overload_add (xv, yv, order)
1990: SV *xv
1991: SV *yv
1992: SV *order
1993: ALIAS:
1994: GMP::Mpq::overload_sub = 1
1995: GMP::Mpq::overload_mul = 2
1996: GMP::Mpq::overload_div = 3
1997: PREINIT:
1998: static const struct {
1999: void (*op) (mpq_ptr, mpq_srcptr, mpq_srcptr);
2000: } table[] = {
2001: { mpq_add }, /* 0 */
2002: { mpq_sub }, /* 1 */
2003: { mpq_mul }, /* 2 */
2004: { mpq_div }, /* 3 */
2005: };
2006: CODE:
2007: TRACE (printf ("%s binary\n", mpf_class));
2008: assert_table (ix);
2009: if (order == &PL_sv_yes)
2010: SV_PTR_SWAP (xv, yv);
2011: RETVAL = new_mpq();
2012: (*table[ix].op) (RETVAL->m,
2013: coerce_mpq (tmp_mpq_0, xv),
2014: coerce_mpq (tmp_mpq_1, yv));
2015: OUTPUT:
2016: RETVAL
2017:
2018:
2019: void
2020: overload_addeq (x, y, o)
2021: mpq_assume x
2022: mpq_coerce y
2023: order_noswap o
2024: ALIAS:
2025: GMP::Mpq::overload_subeq = 1
2026: GMP::Mpq::overload_muleq = 2
2027: GMP::Mpq::overload_diveq = 3
2028: PREINIT:
2029: static const struct {
2030: void (*op) (mpq_ptr, mpq_srcptr, mpq_srcptr);
2031: } table[] = {
2032: { mpq_add }, /* 0 */
2033: { mpq_sub }, /* 1 */
2034: { mpq_mul }, /* 2 */
2035: { mpq_div }, /* 3 */
2036: };
2037: PPCODE:
2038: assert_table (ix);
2039: (*table[ix].op) (x->m, x->m, y);
2040: XPUSHs(ST(0));
2041:
2042:
2043: mpq
2044: overload_lshift (qv, nv, order)
2045: SV *qv
2046: SV *nv
2047: SV *order
2048: ALIAS:
2049: GMP::Mpq::overload_rshift = 1
2050: GMP::Mpq::overload_pow = 2
2051: PREINIT:
2052: static const struct {
2053: void (*op) (mpq_ptr, mpq_srcptr, unsigned long);
2054: } table[] = {
2055: { mpq_mul_2exp }, /* 0 */
2056: { mpq_div_2exp }, /* 1 */
2057: { x_mpq_pow_ui }, /* 2 */
2058: };
2059: CODE:
2060: assert_table (ix);
2061: if (order == &PL_sv_yes)
2062: SV_PTR_SWAP (qv, nv);
2063: RETVAL = new_mpq();
2064: (*table[ix].op) (RETVAL->m, coerce_mpq (RETVAL->m, qv), coerce_ulong (nv));
2065: OUTPUT:
2066: RETVAL
2067:
2068:
2069: void
2070: overload_lshifteq (q, n, o)
2071: mpq_assume q
2072: ulong_coerce n
2073: order_noswap o
2074: ALIAS:
2075: GMP::Mpq::overload_rshifteq = 1
2076: GMP::Mpq::overload_poweq = 2
2077: PREINIT:
2078: static const struct {
2079: void (*op) (mpq_ptr, mpq_srcptr, unsigned long);
2080: } table[] = {
2081: { mpq_mul_2exp }, /* 0 */
2082: { mpq_div_2exp }, /* 1 */
2083: { x_mpq_pow_ui }, /* 2 */
2084: };
2085: PPCODE:
2086: assert_table (ix);
2087: (*table[ix].op) (q->m, q->m, n);
2088: XPUSHs(ST(0));
2089:
2090:
2091: void
2092: overload_inc (q, d1, d2)
2093: mpq_assume q
2094: dummy d1
2095: dummy d2
2096: ALIAS:
2097: GMP::Mpq::overload_dec = 1
2098: PREINIT:
2099: static const struct {
2100: void (*op) (mpz_ptr, mpz_srcptr, mpz_srcptr);
2101: } table[] = {
2102: { mpz_add }, /* 0 */
2103: { mpz_sub }, /* 1 */
2104: };
2105: CODE:
2106: assert_table (ix);
2107: (*table[ix].op) (mpq_numref(q->m), mpq_numref(q->m), mpq_denref(q->m));
2108:
2109:
2110: mpq
2111: overload_abs (q, d1, d2)
2112: mpq_assume q
2113: dummy d1
2114: dummy d2
2115: ALIAS:
2116: GMP::Mpq::overload_neg = 1
2117: PREINIT:
2118: static const struct {
2119: void (*op) (mpq_ptr w, mpq_srcptr x);
2120: } table[] = {
2121: { mpq_abs }, /* 0 */
2122: { mpq_neg }, /* 1 */
2123: };
2124: CODE:
2125: assert_table (ix);
2126: RETVAL = new_mpq();
2127: (*table[ix].op) (RETVAL->m, q->m);
2128: OUTPUT:
2129: RETVAL
2130:
2131:
2132: int
2133: overload_spaceship (x, y, order)
2134: mpq_assume x
2135: mpq_coerce y
2136: SV *order
2137: CODE:
2138: RETVAL = mpq_cmp (x->m, y);
2139: RETVAL = SGN (RETVAL);
2140: if (order == &PL_sv_yes)
2141: RETVAL = -RETVAL;
2142: OUTPUT:
2143: RETVAL
2144:
2145:
2146: bool
2147: overload_bool (q, d1, d2)
2148: mpq_assume q
2149: dummy d1
2150: dummy d2
2151: ALIAS:
2152: GMP::Mpq::overload_not = 1
2153: CODE:
2154: RETVAL = (mpq_sgn (q->m) != 0) ^ ix;
2155: OUTPUT:
2156: RETVAL
2157:
2158:
2159: bool
2160: overload_eq (x, yv, d)
2161: mpq_assume x
2162: SV *yv
2163: dummy d
2164: ALIAS:
2165: GMP::Mpq::overload_ne = 1
2166: CODE:
2167: if (SvIOK(yv))
2168: RETVAL = x_mpq_equal_si (x->m, SvIVX(yv), 1L);
2169: else if (SvROK(yv))
2170: {
2171: if (sv_derived_from (yv, mpz_class))
2172: RETVAL = x_mpq_equal_z (x->m, SvMPZ(yv)->m);
2173: else if (sv_derived_from (yv, mpq_class))
2174: RETVAL = mpq_equal (x->m, SvMPQ(yv)->m);
2175: else
2176: goto coerce;
2177: }
2178: else
2179: {
2180: coerce:
2181: RETVAL = mpq_equal (x->m, coerce_mpq (tmp_mpq_0, yv));
2182: }
2183: RETVAL ^= ix;
2184: OUTPUT:
2185: RETVAL
2186:
2187:
2188: void
2189: canonicalize (q)
2190: mpq q
2191: CODE:
2192: mpq_canonicalize (q->m);
2193:
2194:
2195: mpq
2196: inv (q)
2197: mpq_coerce q
2198: CODE:
2199: RETVAL = new_mpq();
2200: mpq_inv (RETVAL->m, q);
2201: OUTPUT:
2202: RETVAL
2203:
2204:
2205: mpz
2206: num (q)
2207: mpq q
2208: ALIAS:
2209: GMP::Mpq::den = 1
2210: CODE:
2211: RETVAL = new_mpz();
2212: mpz_set (RETVAL->m, (ix == 0 ? mpq_numref(q->m) : mpq_denref(q->m)));
2213: OUTPUT:
2214: RETVAL
2215:
2216:
2217:
2218: #------------------------------------------------------------------------------
2219:
2220: MODULE = GMP PACKAGE = GMP::Mpf
2221:
2222:
2223: mpf
2224: mpf (...)
2225: ALIAS:
2226: GMP::Mpf::new = 1
2227: PREINIT:
2228: unsigned long prec;
2229: CODE:
2230: TRACE (printf ("%s new\n", mpf_class));
2231: if (items > 2)
2232: croak ("%s new: invalid arguments", mpf_class);
2233: prec = (items == 2 ? coerce_ulong (ST(1)) : mpf_get_default_prec());
2234: RETVAL = new_mpf (prec);
2235: if (items >= 1)
2236: my_mpf_set_sv (RETVAL, ST(0));
2237: OUTPUT:
2238: RETVAL
2239:
2240:
2241: mpf
2242: overload_constant (sv, d1, d2, ...)
2243: SV *sv
2244: dummy d1
2245: dummy d2
2246: PREINIT:
2247: mpf f;
2248: CODE:
2249: assert (SvPOK (sv));
2250: TRACE (printf ("%s constant: %s\n", mpq_class, SvPVX(sv)));
2251: RETVAL = new_mpf (mpf_get_default_prec());
2252: my_mpf_set_svstr (RETVAL, sv);
2253: OUTPUT:
2254: RETVAL
2255:
2256:
2257: mpf
2258: overload_copy (f, d1, d2)
2259: mpf_assume f
2260: dummy d1
2261: dummy d2
2262: CODE:
2263: TRACE (printf ("%s copy\n", mpf_class));
2264: RETVAL = new_mpf (mpf_get_prec (f));
2265: mpf_set (RETVAL, f);
2266: OUTPUT:
2267: RETVAL
2268:
2269:
2270: void
2271: DESTROY (f)
2272: mpf_assume f
2273: CODE:
2274: TRACE (printf ("%s DESTROY %p\n", mpf_class, f));
2275: mpf_clear (f);
2276: Safefree (f);
2277: assert_support (mpf_count--);
2278: TRACE_ACTIVE ();
2279:
2280:
2281: mpf
2282: overload_add (x, y, order)
2283: mpf_assume x
2284: mpf_coerce_st0 y
2285: SV *order
2286: ALIAS:
2287: GMP::Mpf::overload_sub = 1
2288: GMP::Mpf::overload_mul = 2
2289: GMP::Mpf::overload_div = 3
2290: PREINIT:
2291: static const struct {
2292: void (*op) (mpf_ptr, mpf_srcptr, mpf_srcptr);
2293: } table[] = {
2294: { mpf_add }, /* 0 */
2295: { mpf_sub }, /* 1 */
2296: { mpf_mul }, /* 2 */
2297: { mpf_div }, /* 3 */
2298: };
2299: unsigned long prec;
2300: CODE:
2301: assert_table (ix);
2302: RETVAL = new_mpf (mpf_get_prec (x));
2303: if (order == &PL_sv_yes)
2304: MPF_PTR_SWAP (x, y);
2305: (*table[ix].op) (RETVAL, x, y);
2306: OUTPUT:
2307: RETVAL
2308:
2309:
2310: void
2311: overload_addeq (x, y, o)
2312: mpf_assume x
2313: mpf_coerce_st0 y
2314: order_noswap o
2315: ALIAS:
2316: GMP::Mpf::overload_subeq = 1
2317: GMP::Mpf::overload_muleq = 2
2318: GMP::Mpf::overload_diveq = 3
2319: PREINIT:
2320: static const struct {
2321: void (*op) (mpf_ptr, mpf_srcptr, mpf_srcptr);
2322: } table[] = {
2323: { mpf_add }, /* 0 */
2324: { mpf_sub }, /* 1 */
2325: { mpf_mul }, /* 2 */
2326: { mpf_div }, /* 3 */
2327: };
2328: PPCODE:
2329: assert_table (ix);
2330: (*table[ix].op) (x, x, y);
2331: XPUSHs(ST(0));
2332:
2333:
2334: mpf
2335: overload_lshift (fv, nv, order)
2336: SV *fv
2337: SV *nv
2338: SV *order
2339: ALIAS:
2340: GMP::Mpf::overload_rshift = 1
2341: GMP::Mpf::overload_pow = 2
2342: PREINIT:
2343: static const struct {
2344: void (*op) (mpf_ptr, mpf_srcptr, unsigned long);
2345: } table[] = {
2346: { mpf_mul_2exp }, /* 0 */
2347: { mpf_div_2exp }, /* 1 */
2348: { mpf_pow_ui }, /* 2 */
2349: };
2350: mpf f;
2351: unsigned long prec;
2352: CODE:
2353: assert_table (ix);
2354: MPF_ASSUME (f, fv);
2355: prec = mpf_get_prec (f);
2356: if (order == &PL_sv_yes)
2357: SV_PTR_SWAP (fv, nv);
2358: f = coerce_mpf (tmp_mpf_0, fv, prec);
2359: RETVAL = new_mpf (prec);
2360: (*table[ix].op) (RETVAL, f, coerce_ulong (nv));
2361: OUTPUT:
2362: RETVAL
2363:
2364:
2365: void
2366: overload_lshifteq (f, n, o)
2367: mpf_assume f
2368: ulong_coerce n
2369: order_noswap o
2370: ALIAS:
2371: GMP::Mpf::overload_rshifteq = 1
2372: GMP::Mpf::overload_poweq = 2
2373: PREINIT:
2374: static const struct {
2375: void (*op) (mpf_ptr, mpf_srcptr, unsigned long);
2376: } table[] = {
2377: { mpf_mul_2exp }, /* 0 */
2378: { mpf_div_2exp }, /* 1 */
2379: { mpf_pow_ui }, /* 2 */
2380: };
2381: PPCODE:
2382: assert_table (ix);
2383: (*table[ix].op) (f, f, n);
2384: XPUSHs(ST(0));
2385:
2386:
2387: mpf
2388: overload_abs (f, d1, d2)
2389: mpf_assume f
2390: dummy d1
2391: dummy d2
2392: ALIAS:
2393: GMP::Mpf::overload_neg = 1
2394: GMP::Mpf::overload_sqrt = 2
2395: PREINIT:
2396: static const struct {
2397: void (*op) (mpf_ptr w, mpf_srcptr x);
2398: } table[] = {
2399: { mpf_abs }, /* 0 */
2400: { mpf_neg }, /* 1 */
2401: { mpf_sqrt }, /* 2 */
2402: };
2403: CODE:
2404: assert_table (ix);
2405: RETVAL = new_mpf (mpf_get_prec (f));
2406: (*table[ix].op) (RETVAL, f);
2407: OUTPUT:
2408: RETVAL
2409:
2410:
2411: void
2412: overload_inc (f, d1, d2)
2413: mpf_assume f
2414: dummy d1
2415: dummy d2
2416: ALIAS:
2417: GMP::Mpf::overload_dec = 1
2418: PREINIT:
2419: static const struct {
2420: void (*op) (mpf_ptr w, mpf_srcptr x, unsigned long y);
2421: } table[] = {
2422: { mpf_add_ui }, /* 0 */
2423: { mpf_sub_ui }, /* 1 */
2424: };
2425: CODE:
2426: assert_table (ix);
2427: (*table[ix].op) (f, f, 1L);
2428:
2429:
2430: int
2431: overload_spaceship (xv, yv, order)
2432: SV *xv
2433: SV *yv
2434: SV *order
2435: PREINIT:
2436: mpf x;
2437: CODE:
2438: MPF_ASSUME (x, xv);
2439: if (SvIOK(yv))
2440: RETVAL = mpf_cmp_si (x, SvIVX(yv));
2441: else if (SvNOK(yv))
2442: RETVAL = mpf_cmp_d (x, SvNVX(yv));
2443: else if (SvPOKorp(yv))
2444: {
2445: STRLEN len;
2446: const char *str = SvPV (yv, len);
2447: /* enough for all digits of the string */
2448: tmp_mpf_set_prec (tmp_mpf_0, strlen(str)+64);
2449: if (mpf_set_str (tmp_mpf_0->m, str, 10) != 0)
2450: croak ("%s <=>: invalid string format", mpf_class);
2451: RETVAL = mpf_cmp (x, tmp_mpf_0->m);
2452: }
2453: else if (SvROK(yv))
2454: {
2455: if (sv_derived_from (yv, mpz_class))
2456: RETVAL = - x_mpz_cmp_f (SvMPZ(yv)->m, x);
2457: else if (sv_derived_from (yv, mpf_class))
2458: RETVAL = mpf_cmp (x, SvMPF(yv));
2459: else
2460: goto use_mpq;
2461: }
2462: else
2463: {
2464: use_mpq:
2465: RETVAL = mpq_cmp (coerce_mpq (tmp_mpq_0, xv),
2466: coerce_mpq (tmp_mpq_1, yv));
2467: }
2468: RETVAL = SGN (RETVAL);
2469: if (order == &PL_sv_yes)
2470: RETVAL = -RETVAL;
2471: OUTPUT:
2472: RETVAL
2473:
2474:
2475: bool
2476: overload_bool (f, d1, d2)
2477: mpf_assume f
2478: dummy d1
2479: dummy d2
2480: ALIAS:
2481: GMP::Mpf::overload_not = 1
2482: CODE:
2483: RETVAL = (mpf_sgn (f) != 0) ^ ix;
2484: OUTPUT:
2485: RETVAL
2486:
2487:
2488: mpf
2489: ceil (f)
2490: mpf_coerce_def f
2491: ALIAS:
2492: GMP::Mpf::floor = 1
2493: GMP::Mpf::trunc = 2
2494: PREINIT:
2495: static const struct {
2496: void (*op) (mpf_ptr w, mpf_srcptr x);
2497: } table[] = {
2498: { mpf_ceil }, /* 0 */
2499: { mpf_floor }, /* 1 */
2500: { mpf_trunc }, /* 2 */
2501: };
2502: CODE:
2503: assert_table (ix);
2504: RETVAL = new_mpf (mpf_get_prec (f));
2505: (*table[ix].op) (RETVAL, f);
2506: OUTPUT:
2507: RETVAL
2508:
2509:
2510: unsigned long
2511: get_default_prec ()
2512: CODE:
2513: RETVAL = mpf_get_default_prec();
2514: OUTPUT:
2515: RETVAL
2516:
2517:
2518: unsigned long
2519: get_prec (f)
2520: mpf_coerce_def f
2521: CODE:
2522: RETVAL = mpf_get_prec (f);
2523: OUTPUT:
2524: RETVAL
2525:
2526:
2527: bool
2528: mpf_eq (xv, yv, bits)
2529: SV *xv
2530: SV *yv
2531: ulong_coerce bits
2532: PREINIT:
2533: mpf x, y;
2534: unsigned long prec;
2535: CODE:
2536: TRACE (printf ("%s eq\n", mpf_class));
2537: COERCE_MPF_PAIR (prec, x,xv, y,yv);
2538: RETVAL = mpf_eq (x, y, bits);
2539: OUTPUT:
2540: RETVAL
2541:
2542:
2543: mpf
2544: reldiff (xv, yv)
2545: SV *xv
2546: SV *yv
2547: PREINIT:
2548: mpf x, y;
2549: unsigned long prec;
2550: CODE:
2551: TRACE (printf ("%s reldiff\n", mpf_class));
2552: COERCE_MPF_PAIR (prec, x,xv, y,yv);
2553: RETVAL = new_mpf (prec);
2554: mpf_reldiff (RETVAL, x, y);
2555: OUTPUT:
2556: RETVAL
2557:
2558:
2559: void
2560: set_default_prec (prec)
2561: ulong_coerce prec
2562: CODE:
2563: TRACE (printf ("%s set_default_prec %lu\n", mpf_class, prec));
2564: mpf_set_default_prec (prec);
2565:
2566:
2567: void
2568: set_prec (sv, prec)
2569: SV *sv
2570: ulong_coerce prec
2571: PREINIT:
2572: mpf_ptr old_f, new_f;
2573: CODE:
2574: TRACE (printf ("%s set_prec to %lu\n", mpf_class, prec));
2575: if (SvROK (sv) && sv_derived_from (sv, mpf_class))
2576: {
2577: old_f = SvMPF(sv);
2578: if (SvREFCNT(SvRV(sv)) == 1)
2579: mpf_set_prec (old_f, prec);
2580: else
2581: {
2582: TRACE (printf (" fork new mpf\n"));
2583: new_f = new_mpf (prec);
2584: mpf_set (new_f, old_f);
2585: goto setref;
2586: }
2587: }
2588: else
2589: {
2590: TRACE (printf (" coerce to mpf\n"));
2591: new_f = new_mpf (prec);
2592: my_mpf_set_sv (new_f, sv);
2593: setref:
2594: sv_setref_pv (sv, mpf_class, new_f);
2595: }
2596:
2597:
2598:
2599: #------------------------------------------------------------------------------
2600:
2601: MODULE = GMP PACKAGE = GMP::Rand
2602:
2603: randstate
2604: new (...)
2605: ALIAS:
2606: GMP::Rand::randstate = 1
2607: CODE:
2608: TRACE (printf ("%s new\n", rand_class));
2609: New (GMP_MALLOC_ID, RETVAL, 1, __gmp_randstate_struct);
2610: TRACE (printf (" RETVAL %p\n", RETVAL));
2611: assert_support (rand_count++);
2612: TRACE_ACTIVE ();
2613:
2614: if (items == 0)
2615: {
2616: gmp_randinit_default (RETVAL);
2617: }
2618: else
2619: {
2620: STRLEN len;
2621: const char *method = SvPV (ST(0), len);
2622: assert (len == strlen (method));
2623: if (strcmp (method, "lc_2exp") == 0)
2624: {
2625: if (items != 4)
2626: goto invalid;
2627: gmp_randinit_lc_2exp (RETVAL,
2628: coerce_mpz (tmp_mpz_0, ST(1)),
2629: coerce_ulong (ST(2)),
2630: coerce_ulong (ST(3)));
2631: }
2632: else if (strcmp (method, "lc_2exp_size") == 0)
2633: {
2634: if (items != 2)
2635: goto invalid;
2636: if (! gmp_randinit_lc_2exp_size (RETVAL, coerce_ulong (ST(1))))
2637: {
2638: Safefree (RETVAL);
2639: XSRETURN_UNDEF;
2640: }
2641: }
2642: else
2643: {
2644: invalid:
2645: croak ("%s new: invalid arguments", rand_class);
2646: }
2647: }
2648: OUTPUT:
2649: RETVAL
2650:
2651:
2652: void
2653: DESTROY (r)
2654: randstate r
2655: CODE:
2656: TRACE (printf ("%s DESTROY\n", rand_class));
2657: gmp_randclear (r);
2658: Safefree (r);
2659: assert_support (rand_count--);
2660: TRACE_ACTIVE ();
2661:
2662:
2663: void
2664: seed (r, z)
2665: randstate r
2666: mpz_coerce z
2667: CODE:
2668: gmp_randseed (r, z);
2669:
2670:
2671: mpz
2672: mpz_urandomb (r, bits)
2673: randstate r
2674: ulong_coerce bits
2675: ALIAS:
2676: GMP::Rand::mpz_rrandomb = 1
2677: PREINIT:
2678: static const struct {
2679: void (*fun) (mpz_ptr, gmp_randstate_t r, unsigned long bits);
2680: } table[] = {
2681: { mpz_urandomb }, /* 0 */
2682: { mpz_rrandomb }, /* 1 */
2683: };
2684: CODE:
2685: assert_table (ix);
2686: RETVAL = new_mpz();
2687: (*table[ix].fun) (RETVAL->m, r, bits);
2688: OUTPUT:
2689: RETVAL
2690:
2691:
2692: mpz
2693: mpz_urandomm (r, m)
2694: randstate r
2695: mpz_coerce m
2696: CODE:
2697: RETVAL = new_mpz();
2698: mpz_urandomm (RETVAL->m, r, m);
2699: OUTPUT:
2700: RETVAL
2701:
2702:
2703: mpf
2704: mpf_urandomb (r, bits)
2705: randstate r
2706: ulong_coerce bits
2707: CODE:
2708: RETVAL = new_mpf (bits);
2709: mpf_urandomb (RETVAL, r, bits);
2710: OUTPUT:
2711: RETVAL
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>