Annotation of OpenXM_contrib/gmp/demos/perl/GMP.xs, Revision 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>