| /* GMP module external subroutines. |
| |
| Copyright 2001-2003, 2015 Free Software Foundation, Inc. |
| |
| This file is part of the GNU MP Library. |
| |
| The GNU MP Library is free software; you can redistribute it and/or modify |
| it under the terms of either: |
| |
| * the GNU Lesser General Public License as published by the Free |
| Software Foundation; either version 3 of the License, or (at your |
| option) any later version. |
| |
| or |
| |
| * the GNU General Public License as published by the Free Software |
| Foundation; either version 2 of the License, or (at your option) any |
| later version. |
| |
| or both in parallel, as here. |
| |
| The GNU MP Library is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
| or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| for more details. |
| |
| You should have received copies of the GNU General Public License and the |
| GNU Lesser General Public License along with the GNU MP Library. If not, |
| see https://www.gnu.org/licenses/. |
| |
| |
| /* Notes: |
| |
| Routines are grouped with the alias feature and a table of function |
| pointers where possible, since each xsub routine ends up with quite a bit |
| of code size. Different combinations of arguments and return values have |
| to be separate though. |
| |
| The "INTERFACE:" feature isn't available in perl 5.005 and so isn't used. |
| "ALIAS:" requires a table lookup with CvXSUBANY(cv).any_i32 (which is |
| "ix") whereas "INTERFACE:" would have CvXSUBANY(cv).any_dptr as the |
| function pointer immediately. |
| |
| Mixed-type swapped-order assignments like "$a = 123; $a += mpz(456);" |
| invoke the plain overloaded "+", not "+=", which makes life easier. |
| |
| mpz_assume etc types are used with the overloaded operators since such |
| operators are always called with a class object as the first argument, we |
| don't need an sv_derived_from() lookup to check. There's assert()s in |
| MPX_ASSUME() for this though. |
| |
| The overload_constant routines reached via overload::constant get 4 |
| arguments in perl 5.6, not the 3 as documented. This is apparently a |
| bug, using "..." lets us ignore the extra one. |
| |
| There's only a few "si" functions in gmp, so usually SvIV values get |
| handled with an mpz_set_si into a temporary and then a full precision mpz |
| routine. This is reasonably efficient. |
| |
| Argument types are checked, with a view to preserving all bits in the |
| operand. Perl is a bit looser in its arithmetic, allowing rounding or |
| truncation to an intended operand type (IV, UV or NV). |
| |
| Bugs: |
| |
| The memory leak detection attempted in GMP::END() doesn't work when mpz's |
| are created as constants because END() is called before they're |
| destroyed. What's the right place to hook such a check? |
| |
| See the bugs section of GMP.pm too. */ |
| |
| |
| /* Comment this out to get assertion checking. */ |
| #define NDEBUG |
| |
| /* Change this to "#define TRACE(x) x" for some diagnostics. */ |
| #define TRACE(x) |
| |
| |
| #include <assert.h> |
| #include <float.h> |
| |
| #include "EXTERN.h" |
| #include "perl.h" |
| #include "XSUB.h" |
| #include "patchlevel.h" |
| |
| #include "gmp.h" |
| |
| |
| /* Perl 5.005 doesn't have SvIsUV, only 5.6 and up. |
| Perl 5.8 has SvUOK, but not 5.6, so we don't use that. */ |
| #ifndef SvIsUV |
| #define SvIsUV(sv) 0 |
| #endif |
| #ifndef SvUVX |
| #define SvUVX(sv) (croak("GMP: oops, shouldn't be using SvUVX"), 0) |
| #endif |
| |
| |
| /* Code which doesn't check anything itself, but exists to support other |
| assert()s. */ |
| #ifdef NDEBUG |
| #define assert_support(x) |
| #else |
| #define assert_support(x) x |
| #endif |
| |
| /* LONG_MAX + 1 and ULONG_MAX + 1, as a doubles */ |
| #define LONG_MAX_P1_AS_DOUBLE ((double) ((unsigned long) LONG_MAX + 1)) |
| #define ULONG_MAX_P1_AS_DOUBLE (2.0 * (double) ((unsigned long) ULONG_MAX/2 + 1)) |
| |
| /* Check for perl version "major.minor". |
| Perl 5.004 doesn't have PERL_REVISION and PERL_VERSION, but that's ok, |
| we're only interested in tests above that. */ |
| #if defined (PERL_REVISION) && defined (PERL_VERSION) |
| #define PERL_GE(major,minor) \ |
| (PERL_REVISION > (major) \ |
| || ((major) == PERL_REVISION && PERL_VERSION >= (minor))) |
| #else |
| #define PERL_GE(major,minor) (0) |
| #endif |
| #define PERL_LT(major,minor) (! PERL_GE(major,minor)) |
| |
| /* sv_derived_from etc in 5.005 took "char *" rather than "const char *". |
| Avoid some compiler warnings by using const only where it works. */ |
| #if PERL_LT (5,6) |
| #define classconst |
| #else |
| #define classconst const |
| #endif |
| |
| /* In a MINGW or Cygwin DLL build of gmp, the various gmp functions are |
| given with dllimport directives, which prevents them being used as |
| initializers for constant data. We give function tables as |
| "static_functable const ...", which is normally "static const", but for |
| mingw expands to just "const" making the table an automatic with a |
| run-time initializer. |
| |
| In gcc 3.3.1, the function tables initialized like this end up getting |
| all the __imp__foo values fetched, even though just one or two will be |
| used. This is wasteful, but probably not too bad. */ |
| |
| #if defined (__MINGW32__) || defined (__CYGWIN__) |
| #define static_functable |
| #else |
| #define static_functable static |
| #endif |
| |
| #define GMP_MALLOC_ID 42 |
| |
| static classconst char mpz_class[] = "GMP::Mpz"; |
| static classconst char mpq_class[] = "GMP::Mpq"; |
| static classconst char mpf_class[] = "GMP::Mpf"; |
| static classconst char rand_class[] = "GMP::Rand"; |
| |
| static HV *mpz_class_hv; |
| static HV *mpq_class_hv; |
| static HV *mpf_class_hv; |
| |
| assert_support (static long mpz_count = 0;) |
| assert_support (static long mpq_count = 0;) |
| assert_support (static long mpf_count = 0;) |
| assert_support (static long rand_count = 0;) |
| |
| #define TRACE_ACTIVE() \ |
| assert_support \ |
| (TRACE (printf (" active %ld mpz, %ld mpq, %ld mpf, %ld randstate\n", \ |
| mpz_count, mpq_count, mpf_count, rand_count))) |
| |
| |
| /* Each "struct mpz_elem" etc is an mpz_t with a link field tacked on the |
| end so they can be held on a linked list. */ |
| |
| #define CREATE_MPX(type) \ |
| \ |
| /* must have mpz_t etc first, for sprintf below */ \ |
| struct type##_elem { \ |
| type##_t m; \ |
| struct type##_elem *next; \ |
| }; \ |
| typedef struct type##_elem *type; \ |
| typedef struct type##_elem *type##_assume; \ |
| typedef type##_ptr type##_coerce; \ |
| \ |
| static type type##_freelist = NULL; \ |
| \ |
| static type \ |
| new_##type (void) \ |
| { \ |
| type p; \ |
| TRACE (printf ("new %s\n", type##_class)); \ |
| if (type##_freelist != NULL) \ |
| { \ |
| p = type##_freelist; \ |
| type##_freelist = type##_freelist->next; \ |
| } \ |
| else \ |
| { \ |
| New (GMP_MALLOC_ID, p, 1, struct type##_elem); \ |
| type##_init (p->m); \ |
| } \ |
| TRACE (printf (" p=%p\n", p)); \ |
| assert_support (type##_count++); \ |
| TRACE_ACTIVE (); \ |
| return p; \ |
| } \ |
| |
| CREATE_MPX (mpz) |
| CREATE_MPX (mpq) |
| |
| typedef mpf_ptr mpf; |
| typedef mpf_ptr mpf_assume; |
| typedef mpf_ptr mpf_coerce_st0; |
| typedef mpf_ptr mpf_coerce_def; |
| |
| |
| static mpf |
| new_mpf (unsigned long prec) |
| { |
| mpf p; |
| New (GMP_MALLOC_ID, p, 1, __mpf_struct); |
| mpf_init2 (p, prec); |
| TRACE (printf (" mpf p=%p\n", p)); |
| assert_support (mpf_count++); |
| TRACE_ACTIVE (); |
| return p; |
| } |
| |
| |
| /* tmp_mpf_t records an allocated precision with an mpf_t so changes of |
| precision can be done with just an mpf_set_prec_raw. */ |
| |
| struct tmp_mpf_struct { |
| mpf_t m; |
| unsigned long allocated_prec; |
| }; |
| typedef const struct tmp_mpf_struct *tmp_mpf_srcptr; |
| typedef struct tmp_mpf_struct *tmp_mpf_ptr; |
| typedef struct tmp_mpf_struct tmp_mpf_t[1]; |
| |
| #define tmp_mpf_init(f) \ |
| do { \ |
| mpf_init (f->m); \ |
| f->allocated_prec = mpf_get_prec (f->m); \ |
| } while (0) |
| |
| static void |
| tmp_mpf_grow (tmp_mpf_ptr f, unsigned long prec) |
| { |
| mpf_set_prec_raw (f->m, f->allocated_prec); |
| mpf_set_prec (f->m, prec); |
| f->allocated_prec = mpf_get_prec (f->m); |
| } |
| |
| #define tmp_mpf_shrink(f) tmp_mpf_grow (f, 1L) |
| |
| #define tmp_mpf_set_prec(f,prec) \ |
| do { \ |
| if (prec > f->allocated_prec) \ |
| tmp_mpf_grow (f, prec); \ |
| else \ |
| mpf_set_prec_raw (f->m, prec); \ |
| } while (0) |
| |
| |
| static mpz_t tmp_mpz_0, tmp_mpz_1, tmp_mpz_2; |
| static mpq_t tmp_mpq_0, tmp_mpq_1; |
| static tmp_mpf_t tmp_mpf_0, tmp_mpf_1; |
| |
| /* for GMP::Mpz::export */ |
| #define tmp_mpz_4 tmp_mpz_2 |
| |
| |
| #define FREE_MPX_FREELIST(p,type) \ |
| do { \ |
| TRACE (printf ("free %s\n", type##_class)); \ |
| p->next = type##_freelist; \ |
| type##_freelist = p; \ |
| assert_support (type##_count--); \ |
| TRACE_ACTIVE (); \ |
| assert (type##_count >= 0); \ |
| } while (0) |
| |
| /* this version for comparison, if desired */ |
| #define FREE_MPX_NOFREELIST(p,type) \ |
| do { \ |
| TRACE (printf ("free %s\n", type##_class)); \ |
| type##_clear (p->m); \ |
| Safefree (p); \ |
| assert_support (type##_count--); \ |
| TRACE_ACTIVE (); \ |
| assert (type##_count >= 0); \ |
| } while (0) |
| |
| #define free_mpz(z) FREE_MPX_FREELIST (z, mpz) |
| #define free_mpq(q) FREE_MPX_FREELIST (q, mpq) |
| |
| |
| /* Return a new mortal SV holding the given mpx_ptr pointer. |
| class_hv should be one of mpz_class_hv etc. */ |
| #define MPX_NEWMORTAL(mpx_ptr, class_hv) \ |
| sv_bless (sv_setref_pv (sv_newmortal(), NULL, mpx_ptr), class_hv) |
| |
| /* Aliases for use in typemaps */ |
| typedef char *malloced_string; |
| typedef const char *const_string; |
| typedef const char *const_string_assume; |
| typedef char *string; |
| typedef SV *order_noswap; |
| typedef SV *dummy; |
| typedef SV *SV_copy_0; |
| typedef unsigned long ulong_coerce; |
| typedef __gmp_randstate_struct *randstate; |
| typedef UV gmp_UV; |
| |
| #define SvMPX(s,type) ((type) SvIV((SV*) SvRV(s))) |
| #define SvMPZ(s) SvMPX(s,mpz) |
| #define SvMPQ(s) SvMPX(s,mpq) |
| #define SvMPF(s) SvMPX(s,mpf) |
| #define SvRANDSTATE(s) SvMPX(s,randstate) |
| |
| #define MPX_ASSUME(x,sv,type) \ |
| do { \ |
| assert (sv_derived_from (sv, type##_class)); \ |
| x = SvMPX(sv,type); \ |
| } while (0) |
| |
| #define MPZ_ASSUME(z,sv) MPX_ASSUME(z,sv,mpz) |
| #define MPQ_ASSUME(q,sv) MPX_ASSUME(q,sv,mpq) |
| #define MPF_ASSUME(f,sv) MPX_ASSUME(f,sv,mpf) |
| |
| #define numberof(x) (sizeof (x) / sizeof ((x)[0])) |
| #define SGN(x) ((x)<0 ? -1 : (x) != 0) |
| #define ABS(x) ((x)>=0 ? (x) : -(x)) |
| #define double_integer_p(d) (floor (d) == (d)) |
| |
| #define x_mpq_integer_p(q) \ |
| (mpz_cmp_ui (mpq_denref(q), 1L) == 0) |
| |
| #define assert_table(ix) assert (ix >= 0 && ix < numberof (table)) |
| |
| #define SV_PTR_SWAP(x,y) \ |
| do { SV *__tmp = (x); (x) = (y); (y) = __tmp; } while (0) |
| #define MPF_PTR_SWAP(x,y) \ |
| do { mpf_ptr __tmp = (x); (x) = (y); (y) = __tmp; } while (0) |
| |
| |
| static void |
| class_or_croak (SV *sv, classconst char *cl) |
| { |
| if (! sv_derived_from (sv, cl)) |
| croak("not type %s", cl); |
| } |
| |
| |
| /* These are macros, wrap them in functions. */ |
| static int |
| x_mpz_odd_p (mpz_srcptr z) |
| { |
| return mpz_odd_p (z); |
| } |
| static int |
| x_mpz_even_p (mpz_srcptr z) |
| { |
| return mpz_even_p (z); |
| } |
| |
| static void |
| x_mpq_pow_ui (mpq_ptr r, mpq_srcptr b, unsigned long e) |
| { |
| mpz_pow_ui (mpq_numref(r), mpq_numref(b), e); |
| mpz_pow_ui (mpq_denref(r), mpq_denref(b), e); |
| } |
| |
| |
| static void * |
| my_gmp_alloc (size_t n) |
| { |
| void *p; |
| TRACE (printf ("my_gmp_alloc %u\n", n)); |
| New (GMP_MALLOC_ID, p, n, char); |
| TRACE (printf (" p=%p\n", p)); |
| return p; |
| } |
| |
| static void * |
| my_gmp_realloc (void *p, size_t oldsize, size_t newsize) |
| { |
| TRACE (printf ("my_gmp_realloc %p, %u to %u\n", p, oldsize, newsize)); |
| Renew (p, newsize, char); |
| TRACE (printf (" p=%p\n", p)); |
| return p; |
| } |
| |
| static void |
| my_gmp_free (void *p, size_t n) |
| { |
| TRACE (printf ("my_gmp_free %p %u\n", p, n)); |
| Safefree (p); |
| } |
| |
| |
| #define my_mpx_set_svstr(type) \ |
| static void \ |
| my_##type##_set_svstr (type##_ptr x, SV *sv) \ |
| { \ |
| const char *str; \ |
| STRLEN len; \ |
| TRACE (printf (" my_" #type "_set_svstr\n")); \ |
| assert (SvPOK(sv) || SvPOKp(sv)); \ |
| str = SvPV (sv, len); \ |
| TRACE (printf (" str \"%s\"\n", str)); \ |
| if (type##_set_str (x, str, 0) != 0) \ |
| croak ("%s: invalid string: %s", type##_class, str); \ |
| } |
| |
| my_mpx_set_svstr(mpz) |
| my_mpx_set_svstr(mpq) |
| my_mpx_set_svstr(mpf) |
| |
| |
| /* very slack */ |
| static int |
| x_mpq_cmp_si (mpq_srcptr x, long yn, unsigned long yd) |
| { |
| mpq y; |
| int ret; |
| y = new_mpq (); |
| mpq_set_si (y->m, yn, yd); |
| ret = mpq_cmp (x, y->m); |
| free_mpq (y); |
| return ret; |
| } |
| |
| static int |
| x_mpq_fits_slong_p (mpq_srcptr q) |
| { |
| return x_mpq_cmp_si (q, LONG_MIN, 1L) >= 0 |
| && mpq_cmp_ui (q, LONG_MAX, 1L) <= 0; |
| } |
| |
| static int |
| x_mpz_cmp_q (mpz_ptr x, mpq_srcptr y) |
| { |
| int ret; |
| mpz_set_ui (mpq_denref(tmp_mpq_0), 1L); |
| mpz_swap (mpq_numref(tmp_mpq_0), x); |
| ret = mpq_cmp (tmp_mpq_0, y); |
| mpz_swap (mpq_numref(tmp_mpq_0), x); |
| return ret; |
| } |
| |
| static int |
| x_mpz_cmp_f (mpz_srcptr x, mpf_srcptr y) |
| { |
| tmp_mpf_set_prec (tmp_mpf_0, mpz_sizeinbase (x, 2)); |
| mpf_set_z (tmp_mpf_0->m, x); |
| return mpf_cmp (tmp_mpf_0->m, y); |
| } |
| |
| |
| #define USE_UNKNOWN 0 |
| #define USE_IVX 1 |
| #define USE_UVX 2 |
| #define USE_NVX 3 |
| #define USE_PVX 4 |
| #define USE_MPZ 5 |
| #define USE_MPQ 6 |
| #define USE_MPF 7 |
| |
| /* mg_get is called every time we get a value, even if the private flags are |
| still set from a previous such call. This is the same as as SvIV and |
| friends do. |
| |
| When POK, we use the PV, even if there's an IV or NV available. This is |
| because it's hard to be sure there wasn't any rounding in establishing |
| the IV and/or NV. Cases of overflow, where the PV should definitely be |
| used, are easy enough to spot, but rounding is hard. So although IV or |
| NV would be more efficient, we must use the PV to be sure of getting all |
| the data. Applications should convert once to mpz, mpq or mpf when using |
| a value repeatedly. |
| |
| Zany dual-type scalars like $! where the IV is an error code and the PV |
| is an error description string won't work with this preference for PV, |
| but that's too bad. Such scalars should be rare, and unlikely to be used |
| in bignum calculations. |
| |
| When IOK and NOK are both set, we would prefer to use the IV since it can |
| be converted more efficiently, and because on a 64-bit system the NV may |
| have less bits than the IV. The following rules are applied, |
| |
| - If the NV is not an integer, then we must use that NV, since clearly |
| the IV was merely established by rounding and is not the full value. |
| |
| - In perl prior to 5.8, an NV too big for an IV leaves an overflow value |
| 0xFFFFFFFF. If the NV is too big to fit an IV then clearly it's the NV |
| which is the true value and must be used. |
| |
| - In perl 5.8 and up, such an overflow doesn't set IOK, so that test is |
| unnecessary. However when coming from get-magic, IOKp _is_ set, and we |
| must check for overflow the same as in older perl. |
| |
| FIXME: |
| |
| We'd like to call mg_get just once, but unfortunately sv_derived_from() |
| will call it for each of our checks. We could do a string compare like |
| sv_isa ourselves, but that only tests the exact class, it doesn't |
| recognise subclassing. There doesn't seem to be a public interface to |
| the subclassing tests (in the internal isa_lookup() function). */ |
| |
| int |
| use_sv (SV *sv) |
| { |
| double d; |
| |
| if (SvGMAGICAL(sv)) |
| { |
| mg_get(sv); |
| |
| if (SvPOKp(sv)) |
| return USE_PVX; |
| |
| if (SvIOKp(sv)) |
| { |
| if (SvIsUV(sv)) |
| { |
| if (SvNOKp(sv)) |
| goto u_or_n; |
| return USE_UVX; |
| } |
| else |
| { |
| if (SvNOKp(sv)) |
| goto i_or_n; |
| return USE_IVX; |
| } |
| } |
| |
| if (SvNOKp(sv)) |
| return USE_NVX; |
| |
| goto rok_or_unknown; |
| } |
| |
| if (SvPOK(sv)) |
| return USE_PVX; |
| |
| if (SvIOK(sv)) |
| { |
| if (SvIsUV(sv)) |
| { |
| if (SvNOK(sv)) |
| { |
| if (PERL_LT (5, 8)) |
| { |
| u_or_n: |
| d = SvNVX(sv); |
| if (d >= ULONG_MAX_P1_AS_DOUBLE || d < 0.0) |
| return USE_NVX; |
| } |
| d = SvNVX(sv); |
| if (d != floor (d)) |
| return USE_NVX; |
| } |
| return USE_UVX; |
| } |
| else |
| { |
| if (SvNOK(sv)) |
| { |
| if (PERL_LT (5, 8)) |
| { |
| i_or_n: |
| d = SvNVX(sv); |
| if (d >= LONG_MAX_P1_AS_DOUBLE || d < (double) LONG_MIN) |
| return USE_NVX; |
| } |
| d = SvNVX(sv); |
| if (d != floor (d)) |
| return USE_NVX; |
| } |
| return USE_IVX; |
| } |
| } |
| |
| if (SvNOK(sv)) |
| return USE_NVX; |
| |
| rok_or_unknown: |
| if (SvROK(sv)) |
| { |
| if (sv_derived_from (sv, mpz_class)) |
| return USE_MPZ; |
| if (sv_derived_from (sv, mpq_class)) |
| return USE_MPQ; |
| if (sv_derived_from (sv, mpf_class)) |
| return USE_MPF; |
| } |
| |
| return USE_UNKNOWN; |
| } |
| |
| |
| /* Coerce sv to an mpz. Use tmp to hold the converted value if sv isn't |
| already an mpz (or an mpq of which the numerator can be used). Return |
| the chosen mpz (tmp or the contents of sv). */ |
| |
| static mpz_ptr |
| coerce_mpz_using (mpz_ptr tmp, SV *sv, int use) |
| { |
| switch (use) { |
| case USE_IVX: |
| mpz_set_si (tmp, SvIVX(sv)); |
| return tmp; |
| |
| case USE_UVX: |
| mpz_set_ui (tmp, SvUVX(sv)); |
| return tmp; |
| |
| case USE_NVX: |
| { |
| double d; |
| d = SvNVX(sv); |
| if (! double_integer_p (d)) |
| croak ("cannot coerce non-integer double to mpz"); |
| mpz_set_d (tmp, d); |
| return tmp; |
| } |
| |
| case USE_PVX: |
| my_mpz_set_svstr (tmp, sv); |
| return tmp; |
| |
| case USE_MPZ: |
| return SvMPZ(sv)->m; |
| |
| case USE_MPQ: |
| { |
| mpq q = SvMPQ(sv); |
| if (! x_mpq_integer_p (q->m)) |
| croak ("cannot coerce non-integer mpq to mpz"); |
| return mpq_numref(q->m); |
| } |
| |
| case USE_MPF: |
| { |
| mpf f = SvMPF(sv); |
| if (! mpf_integer_p (f)) |
| croak ("cannot coerce non-integer mpf to mpz"); |
| mpz_set_f (tmp, f); |
| return tmp; |
| } |
| |
| default: |
| croak ("cannot coerce to mpz"); |
| } |
| } |
| static mpz_ptr |
| coerce_mpz (mpz_ptr tmp, SV *sv) |
| { |
| return coerce_mpz_using (tmp, sv, use_sv (sv)); |
| } |
| |
| |
| /* Coerce sv to an mpq. If sv is an mpq then just return that, otherwise |
| use tmp to hold the converted value and return that. */ |
| |
| static mpq_ptr |
| coerce_mpq_using (mpq_ptr tmp, SV *sv, int use) |
| { |
| TRACE (printf ("coerce_mpq_using %p %d\n", tmp, use)); |
| switch (use) { |
| case USE_IVX: |
| mpq_set_si (tmp, SvIVX(sv), 1L); |
| return tmp; |
| |
| case USE_UVX: |
| mpq_set_ui (tmp, SvUVX(sv), 1L); |
| return tmp; |
| |
| case USE_NVX: |
| mpq_set_d (tmp, SvNVX(sv)); |
| return tmp; |
| |
| case USE_PVX: |
| my_mpq_set_svstr (tmp, sv); |
| return tmp; |
| |
| case USE_MPZ: |
| mpq_set_z (tmp, SvMPZ(sv)->m); |
| return tmp; |
| |
| case USE_MPQ: |
| return SvMPQ(sv)->m; |
| |
| case USE_MPF: |
| mpq_set_f (tmp, SvMPF(sv)); |
| return tmp; |
| |
| default: |
| croak ("cannot coerce to mpq"); |
| } |
| } |
| static mpq_ptr |
| coerce_mpq (mpq_ptr tmp, SV *sv) |
| { |
| return coerce_mpq_using (tmp, sv, use_sv (sv)); |
| } |
| |
| |
| static void |
| my_mpf_set_sv_using (mpf_ptr f, SV *sv, int use) |
| { |
| switch (use) { |
| case USE_IVX: |
| mpf_set_si (f, SvIVX(sv)); |
| break; |
| |
| case USE_UVX: |
| mpf_set_ui (f, SvUVX(sv)); |
| break; |
| |
| case USE_NVX: |
| mpf_set_d (f, SvNVX(sv)); |
| break; |
| |
| case USE_PVX: |
| my_mpf_set_svstr (f, sv); |
| break; |
| |
| case USE_MPZ: |
| mpf_set_z (f, SvMPZ(sv)->m); |
| break; |
| |
| case USE_MPQ: |
| mpf_set_q (f, SvMPQ(sv)->m); |
| break; |
| |
| case USE_MPF: |
| mpf_set (f, SvMPF(sv)); |
| break; |
| |
| default: |
| croak ("cannot coerce to mpf"); |
| } |
| } |
| |
| /* Coerce sv to an mpf. If sv is an mpf then just return that, otherwise |
| use tmp to hold the converted value (with prec precision). */ |
| static mpf_ptr |
| coerce_mpf_using (tmp_mpf_ptr tmp, SV *sv, unsigned long prec, int use) |
| { |
| if (use == USE_MPF) |
| return SvMPF(sv); |
| |
| tmp_mpf_set_prec (tmp, prec); |
| my_mpf_set_sv_using (tmp->m, sv, use); |
| return tmp->m; |
| } |
| static mpf_ptr |
| coerce_mpf (tmp_mpf_ptr tmp, SV *sv, unsigned long prec) |
| { |
| return coerce_mpf_using (tmp, sv, prec, use_sv (sv)); |
| } |
| |
| |
| /* Coerce xv to an mpf and store the pointer in x, ditto for yv to x. If |
| one of xv or yv is an mpf then use it for the precision, otherwise use |
| the default precision. */ |
| unsigned long |
| coerce_mpf_pair (mpf *xp, SV *xv, mpf *yp, SV *yv) |
| { |
| int x_use = use_sv (xv); |
| int y_use = use_sv (yv); |
| unsigned long prec; |
| mpf x, y; |
| |
| if (x_use == USE_MPF) |
| { |
| x = SvMPF(xv); |
| prec = mpf_get_prec (x); |
| y = coerce_mpf_using (tmp_mpf_0, yv, prec, y_use); |
| } |
| else |
| { |
| y = coerce_mpf_using (tmp_mpf_0, yv, mpf_get_default_prec(), y_use); |
| prec = mpf_get_prec (y); |
| x = coerce_mpf_using (tmp_mpf_1, xv, prec, x_use); |
| } |
| *xp = x; |
| *yp = y; |
| return prec; |
| } |
| |
| |
| /* Note that SvUV is not used, since it merely treats the signed IV as if it |
| was unsigned. We get an IV and check its sign. */ |
| static unsigned long |
| coerce_ulong (SV *sv) |
| { |
| long n; |
| |
| switch (use_sv (sv)) { |
| case USE_IVX: |
| n = SvIVX(sv); |
| negative_check: |
| if (n < 0) |
| goto range_error; |
| return n; |
| |
| case USE_UVX: |
| return SvUVX(sv); |
| |
| case USE_NVX: |
| { |
| double d; |
| d = SvNVX(sv); |
| if (! double_integer_p (d)) |
| goto integer_error; |
| n = SvIV(sv); |
| } |
| goto negative_check; |
| |
| case USE_PVX: |
| /* FIXME: Check the string is an integer. */ |
| n = SvIV(sv); |
| goto negative_check; |
| |
| case USE_MPZ: |
| { |
| mpz z = SvMPZ(sv); |
| if (! mpz_fits_ulong_p (z->m)) |
| goto range_error; |
| return mpz_get_ui (z->m); |
| } |
| |
| case USE_MPQ: |
| { |
| mpq q = SvMPQ(sv); |
| if (! x_mpq_integer_p (q->m)) |
| goto integer_error; |
| if (! mpz_fits_ulong_p (mpq_numref (q->m))) |
| goto range_error; |
| return mpz_get_ui (mpq_numref (q->m)); |
| } |
| |
| case USE_MPF: |
| { |
| mpf f = SvMPF(sv); |
| if (! mpf_integer_p (f)) |
| goto integer_error; |
| if (! mpf_fits_ulong_p (f)) |
| goto range_error; |
| return mpf_get_ui (f); |
| } |
| |
| default: |
| croak ("cannot coerce to ulong"); |
| } |
| |
| integer_error: |
| croak ("not an integer"); |
| |
| range_error: |
| croak ("out of range for ulong"); |
| } |
| |
| |
| static long |
| coerce_long (SV *sv) |
| { |
| switch (use_sv (sv)) { |
| case USE_IVX: |
| return SvIVX(sv); |
| |
| case USE_UVX: |
| { |
| UV u = SvUVX(sv); |
| if (u > (UV) LONG_MAX) |
| goto range_error; |
| return u; |
| } |
| |
| case USE_NVX: |
| { |
| double d = SvNVX(sv); |
| if (! double_integer_p (d)) |
| goto integer_error; |
| return SvIV(sv); |
| } |
| |
| case USE_PVX: |
| /* FIXME: Check the string is an integer. */ |
| return SvIV(sv); |
| |
| case USE_MPZ: |
| { |
| mpz z = SvMPZ(sv); |
| if (! mpz_fits_slong_p (z->m)) |
| goto range_error; |
| return mpz_get_si (z->m); |
| } |
| |
| case USE_MPQ: |
| { |
| mpq q = SvMPQ(sv); |
| if (! x_mpq_integer_p (q->m)) |
| goto integer_error; |
| if (! mpz_fits_slong_p (mpq_numref (q->m))) |
| goto range_error; |
| return mpz_get_si (mpq_numref (q->m)); |
| } |
| |
| case USE_MPF: |
| { |
| mpf f = SvMPF(sv); |
| if (! mpf_integer_p (f)) |
| goto integer_error; |
| if (! mpf_fits_slong_p (f)) |
| goto range_error; |
| return mpf_get_si (f); |
| } |
| |
| default: |
| croak ("cannot coerce to long"); |
| } |
| |
| integer_error: |
| croak ("not an integer"); |
| |
| range_error: |
| croak ("out of range for ulong"); |
| } |
| |
| |
| /* ------------------------------------------------------------------------- */ |
| |
| MODULE = GMP PACKAGE = GMP |
| |
| BOOT: |
| TRACE (printf ("GMP boot\n")); |
| mp_set_memory_functions (my_gmp_alloc, my_gmp_realloc, my_gmp_free); |
| mpz_init (tmp_mpz_0); |
| mpz_init (tmp_mpz_1); |
| mpz_init (tmp_mpz_2); |
| mpq_init (tmp_mpq_0); |
| mpq_init (tmp_mpq_1); |
| tmp_mpf_init (tmp_mpf_0); |
| tmp_mpf_init (tmp_mpf_1); |
| mpz_class_hv = gv_stashpv (mpz_class, 1); |
| mpq_class_hv = gv_stashpv (mpq_class, 1); |
| mpf_class_hv = gv_stashpv (mpf_class, 1); |
| |
| |
| void |
| END() |
| CODE: |
| TRACE (printf ("GMP end\n")); |
| TRACE_ACTIVE (); |
| /* These are not always true, see Bugs at the top of the file. */ |
| /* assert (mpz_count == 0); */ |
| /* assert (mpq_count == 0); */ |
| /* assert (mpf_count == 0); */ |
| /* assert (rand_count == 0); */ |
| |
| |
| const_string |
| version() |
| CODE: |
| RETVAL = gmp_version; |
| OUTPUT: |
| RETVAL |
| |
| |
| bool |
| fits_slong_p (sv) |
| SV *sv |
| CODE: |
| switch (use_sv (sv)) { |
| case USE_IVX: |
| RETVAL = 1; |
| break; |
| |
| case USE_UVX: |
| { |
| UV u = SvUVX(sv); |
| RETVAL = (u <= LONG_MAX); |
| } |
| break; |
| |
| case USE_NVX: |
| { |
| double d = SvNVX(sv); |
| RETVAL = (d >= (double) LONG_MIN && d < LONG_MAX_P1_AS_DOUBLE); |
| } |
| break; |
| |
| case USE_PVX: |
| { |
| STRLEN len; |
| const char *str = SvPV (sv, len); |
| if (mpq_set_str (tmp_mpq_0, str, 0) == 0) |
| RETVAL = x_mpq_fits_slong_p (tmp_mpq_0); |
| else |
| { |
| /* enough precision for a long */ |
| tmp_mpf_set_prec (tmp_mpf_0, 2*mp_bits_per_limb); |
| if (mpf_set_str (tmp_mpf_0->m, str, 10) != 0) |
| croak ("GMP::fits_slong_p invalid string format"); |
| RETVAL = mpf_fits_slong_p (tmp_mpf_0->m); |
| } |
| } |
| break; |
| |
| case USE_MPZ: |
| RETVAL = mpz_fits_slong_p (SvMPZ(sv)->m); |
| break; |
| |
| case USE_MPQ: |
| RETVAL = x_mpq_fits_slong_p (SvMPQ(sv)->m); |
| break; |
| |
| case USE_MPF: |
| RETVAL = mpf_fits_slong_p (SvMPF(sv)); |
| break; |
| |
| default: |
| croak ("GMP::fits_slong_p invalid argument"); |
| } |
| OUTPUT: |
| RETVAL |
| |
| |
| double |
| get_d (sv) |
| SV *sv |
| CODE: |
| switch (use_sv (sv)) { |
| case USE_IVX: |
| RETVAL = (double) SvIVX(sv); |
| break; |
| |
| case USE_UVX: |
| RETVAL = (double) SvUVX(sv); |
| break; |
| |
| case USE_NVX: |
| RETVAL = SvNVX(sv); |
| break; |
| |
| case USE_PVX: |
| { |
| STRLEN len; |
| RETVAL = atof(SvPV(sv, len)); |
| } |
| break; |
| |
| case USE_MPZ: |
| RETVAL = mpz_get_d (SvMPZ(sv)->m); |
| break; |
| |
| case USE_MPQ: |
| RETVAL = mpq_get_d (SvMPQ(sv)->m); |
| break; |
| |
| case USE_MPF: |
| RETVAL = mpf_get_d (SvMPF(sv)); |
| break; |
| |
| default: |
| croak ("GMP::get_d invalid argument"); |
| } |
| OUTPUT: |
| RETVAL |
| |
| |
| void |
| get_d_2exp (sv) |
| SV *sv |
| PREINIT: |
| double ret; |
| long exp; |
| PPCODE: |
| switch (use_sv (sv)) { |
| case USE_IVX: |
| ret = (double) SvIVX(sv); |
| goto use_frexp; |
| |
| case USE_UVX: |
| ret = (double) SvUVX(sv); |
| goto use_frexp; |
| |
| case USE_NVX: |
| { |
| int i_exp; |
| ret = SvNVX(sv); |
| use_frexp: |
| ret = frexp (ret, &i_exp); |
| exp = i_exp; |
| } |
| break; |
| |
| case USE_PVX: |
| /* put strings through mpf to give full exp range */ |
| tmp_mpf_set_prec (tmp_mpf_0, DBL_MANT_DIG); |
| my_mpf_set_svstr (tmp_mpf_0->m, sv); |
| ret = mpf_get_d_2exp (&exp, tmp_mpf_0->m); |
| break; |
| |
| case USE_MPZ: |
| ret = mpz_get_d_2exp (&exp, SvMPZ(sv)->m); |
| break; |
| |
| case USE_MPQ: |
| tmp_mpf_set_prec (tmp_mpf_0, DBL_MANT_DIG); |
| mpf_set_q (tmp_mpf_0->m, SvMPQ(sv)->m); |
| ret = mpf_get_d_2exp (&exp, tmp_mpf_0->m); |
| break; |
| |
| case USE_MPF: |
| ret = mpf_get_d_2exp (&exp, SvMPF(sv)); |
| break; |
| |
| default: |
| croak ("GMP::get_d_2exp invalid argument"); |
| } |
| PUSHs (sv_2mortal (newSVnv (ret))); |
| PUSHs (sv_2mortal (newSViv (exp))); |
| |
| |
| long |
| get_si (sv) |
| SV *sv |
| CODE: |
| switch (use_sv (sv)) { |
| case USE_IVX: |
| RETVAL = SvIVX(sv); |
| break; |
| |
| case USE_UVX: |
| RETVAL = SvUVX(sv); |
| break; |
| |
| case USE_NVX: |
| RETVAL = (long) SvNVX(sv); |
| break; |
| |
| case USE_PVX: |
| RETVAL = SvIV(sv); |
| break; |
| |
| case USE_MPZ: |
| RETVAL = mpz_get_si (SvMPZ(sv)->m); |
| break; |
| |
| case USE_MPQ: |
| mpz_set_q (tmp_mpz_0, SvMPQ(sv)->m); |
| RETVAL = mpz_get_si (tmp_mpz_0); |
| break; |
| |
| case USE_MPF: |
| RETVAL = mpf_get_si (SvMPF(sv)); |
| break; |
| |
| default: |
| croak ("GMP::get_si invalid argument"); |
| } |
| OUTPUT: |
| RETVAL |
| |
| |
| void |
| get_str (sv, ...) |
| SV *sv |
| PREINIT: |
| char *str; |
| mp_exp_t exp; |
| mpz_ptr z; |
| mpq_ptr q; |
| mpf f; |
| int base; |
| int ndigits; |
| PPCODE: |
| TRACE (printf ("GMP::get_str\n")); |
| |
| if (items >= 2) |
| base = coerce_long (ST(1)); |
| else |
| base = 10; |
| TRACE (printf (" base=%d\n", base)); |
| |
| if (items >= 3) |
| ndigits = coerce_long (ST(2)); |
| else |
| ndigits = 10; |
| TRACE (printf (" ndigits=%d\n", ndigits)); |
| |
| EXTEND (SP, 2); |
| |
| switch (use_sv (sv)) { |
| case USE_IVX: |
| mpz_set_si (tmp_mpz_0, SvIVX(sv)); |
| get_tmp_mpz_0: |
| z = tmp_mpz_0; |
| goto get_mpz; |
| |
| case USE_UVX: |
| mpz_set_ui (tmp_mpz_0, SvUVX(sv)); |
| goto get_tmp_mpz_0; |
| |
| case USE_NVX: |
| /* only digits in the original double, not in the coerced form */ |
| if (ndigits == 0) |
| ndigits = DBL_DIG; |
| mpf_set_d (tmp_mpf_0->m, SvNVX(sv)); |
| f = tmp_mpf_0->m; |
| goto get_mpf; |
| |
| case USE_PVX: |
| { |
| /* get_str on a string is not much more than a base conversion */ |
| STRLEN len; |
| str = SvPV (sv, len); |
| if (mpz_set_str (tmp_mpz_0, str, 0) == 0) |
| { |
| z = tmp_mpz_0; |
| goto get_mpz; |
| } |
| else if (mpq_set_str (tmp_mpq_0, str, 0) == 0) |
| { |
| q = tmp_mpq_0; |
| goto get_mpq; |
| } |
| else |
| { |
| /* FIXME: Would like perhaps a precision equivalent to the |
| number of significant digits of the string, in its given |
| base. */ |
| tmp_mpf_set_prec (tmp_mpf_0, strlen(str)); |
| if (mpf_set_str (tmp_mpf_0->m, str, 10) == 0) |
| { |
| f = tmp_mpf_0->m; |
| goto get_mpf; |
| } |
| else |
| croak ("GMP::get_str invalid string format"); |
| } |
| } |
| break; |
| |
| case USE_MPZ: |
| z = SvMPZ(sv)->m; |
| get_mpz: |
| str = mpz_get_str (NULL, base, z); |
| push_str: |
| PUSHs (sv_2mortal (newSVpv (str, 0))); |
| break; |
| |
| case USE_MPQ: |
| q = SvMPQ(sv)->m; |
| get_mpq: |
| str = mpq_get_str (NULL, base, q); |
| goto push_str; |
| |
| case USE_MPF: |
| f = SvMPF(sv); |
| get_mpf: |
| str = mpf_get_str (NULL, &exp, base, 0, f); |
| PUSHs (sv_2mortal (newSVpv (str, 0))); |
| PUSHs (sv_2mortal (newSViv (exp))); |
| break; |
| |
| default: |
| croak ("GMP::get_str invalid argument"); |
| } |
| |
| |
| bool |
| integer_p (sv) |
| SV *sv |
| CODE: |
| switch (use_sv (sv)) { |
| case USE_IVX: |
| case USE_UVX: |
| RETVAL = 1; |
| break; |
| |
| case USE_NVX: |
| RETVAL = double_integer_p (SvNVX(sv)); |
| break; |
| |
| case USE_PVX: |
| { |
| /* FIXME: Maybe this should be done by parsing the string, not by an |
| actual conversion. */ |
| STRLEN len; |
| const char *str = SvPV (sv, len); |
| if (mpq_set_str (tmp_mpq_0, str, 0) == 0) |
| RETVAL = x_mpq_integer_p (tmp_mpq_0); |
| else |
| { |
| /* enough for all digits of the string */ |
| tmp_mpf_set_prec (tmp_mpf_0, strlen(str)+64); |
| if (mpf_set_str (tmp_mpf_0->m, str, 10) == 0) |
| RETVAL = mpf_integer_p (tmp_mpf_0->m); |
| else |
| croak ("GMP::integer_p invalid string format"); |
| } |
| } |
| break; |
| |
| case USE_MPZ: |
| RETVAL = 1; |
| break; |
| |
| case USE_MPQ: |
| RETVAL = x_mpq_integer_p (SvMPQ(sv)->m); |
| break; |
| |
| case USE_MPF: |
| RETVAL = mpf_integer_p (SvMPF(sv)); |
| break; |
| |
| default: |
| croak ("GMP::integer_p invalid argument"); |
| } |
| OUTPUT: |
| RETVAL |
| |
| |
| int |
| sgn (sv) |
| SV *sv |
| CODE: |
| switch (use_sv (sv)) { |
| case USE_IVX: |
| RETVAL = SGN (SvIVX(sv)); |
| break; |
| |
| case USE_UVX: |
| RETVAL = (SvUVX(sv) > 0); |
| break; |
| |
| case USE_NVX: |
| RETVAL = SGN (SvNVX(sv)); |
| break; |
| |
| case USE_PVX: |
| { |
| /* FIXME: Maybe this should be done by parsing the string, not by an |
| actual conversion. */ |
| STRLEN len; |
| const char *str = SvPV (sv, len); |
| if (mpq_set_str (tmp_mpq_0, str, 0) == 0) |
| RETVAL = mpq_sgn (tmp_mpq_0); |
| else |
| { |
| /* enough for all digits of the string */ |
| tmp_mpf_set_prec (tmp_mpf_0, strlen(str)+64); |
| if (mpf_set_str (tmp_mpf_0->m, str, 10) == 0) |
| RETVAL = mpf_sgn (tmp_mpf_0->m); |
| else |
| croak ("GMP::sgn invalid string format"); |
| } |
| } |
| break; |
| |
| case USE_MPZ: |
| RETVAL = mpz_sgn (SvMPZ(sv)->m); |
| break; |
| |
| case USE_MPQ: |
| RETVAL = mpq_sgn (SvMPQ(sv)->m); |
| break; |
| |
| case USE_MPF: |
| RETVAL = mpf_sgn (SvMPF(sv)); |
| break; |
| |
| default: |
| croak ("GMP::sgn invalid argument"); |
| } |
| OUTPUT: |
| RETVAL |
| |
| |
| # currently undocumented |
| void |
| shrink () |
| CODE: |
| #define x_mpz_shrink(z) \ |
| mpz_set_ui (z, 0L); _mpz_realloc (z, 1) |
| #define x_mpq_shrink(q) \ |
| x_mpz_shrink (mpq_numref(q)); x_mpz_shrink (mpq_denref(q)) |
| |
| x_mpz_shrink (tmp_mpz_0); |
| x_mpz_shrink (tmp_mpz_1); |
| x_mpz_shrink (tmp_mpz_2); |
| x_mpq_shrink (tmp_mpq_0); |
| x_mpq_shrink (tmp_mpq_1); |
| tmp_mpf_shrink (tmp_mpf_0); |
| tmp_mpf_shrink (tmp_mpf_1); |
| |
| |
| |
| malloced_string |
| sprintf_internal (fmt, sv) |
| const_string fmt |
| SV *sv |
| CODE: |
| assert (strlen (fmt) >= 3); |
| assert (SvROK(sv)); |
| assert ((sv_derived_from (sv, mpz_class) && fmt[strlen(fmt)-2] == 'Z') |
| || (sv_derived_from (sv, mpq_class) && fmt[strlen(fmt)-2] == 'Q') |
| || (sv_derived_from (sv, mpf_class) && fmt[strlen(fmt)-2] == 'F')); |
| TRACE (printf ("GMP::sprintf_internal\n"); |
| printf (" fmt |%s|\n", fmt); |
| printf (" sv |%p|\n", SvMPZ(sv))); |
| |
| /* cheat a bit here, SvMPZ works for mpq and mpf too */ |
| gmp_asprintf (&RETVAL, fmt, SvMPZ(sv)); |
| |
| TRACE (printf (" result |%s|\n", RETVAL)); |
| OUTPUT: |
| RETVAL |
| |
| |
| |
| #------------------------------------------------------------------------------ |
| |
| MODULE = GMP PACKAGE = GMP::Mpz |
| |
| mpz |
| mpz (...) |
| ALIAS: |
| GMP::Mpz::new = 1 |
| PREINIT: |
| SV *sv; |
| CODE: |
| TRACE (printf ("%s new, ix=%ld, items=%d\n", mpz_class, ix, (int) items)); |
| RETVAL = new_mpz(); |
| |
| switch (items) { |
| case 0: |
| mpz_set_ui (RETVAL->m, 0L); |
| break; |
| |
| case 1: |
| sv = ST(0); |
| TRACE (printf (" use %d\n", use_sv (sv))); |
| switch (use_sv (sv)) { |
| case USE_IVX: |
| mpz_set_si (RETVAL->m, SvIVX(sv)); |
| break; |
| |
| case USE_UVX: |
| mpz_set_ui (RETVAL->m, SvUVX(sv)); |
| break; |
| |
| case USE_NVX: |
| mpz_set_d (RETVAL->m, SvNVX(sv)); |
| break; |
| |
| case USE_PVX: |
| my_mpz_set_svstr (RETVAL->m, sv); |
| break; |
| |
| case USE_MPZ: |
| mpz_set (RETVAL->m, SvMPZ(sv)->m); |
| break; |
| |
| case USE_MPQ: |
| mpz_set_q (RETVAL->m, SvMPQ(sv)->m); |
| break; |
| |
| case USE_MPF: |
| mpz_set_f (RETVAL->m, SvMPF(sv)); |
| break; |
| |
| default: |
| goto invalid; |
| } |
| break; |
| |
| default: |
| invalid: |
| croak ("%s new: invalid arguments", mpz_class); |
| } |
| OUTPUT: |
| RETVAL |
| |
| |
| void |
| overload_constant (str, pv, d1, ...) |
| const_string_assume str |
| SV *pv |
| dummy d1 |
| PREINIT: |
| mpz z; |
| PPCODE: |
| TRACE (printf ("%s constant: %s\n", mpz_class, str)); |
| z = new_mpz(); |
| if (mpz_set_str (z->m, str, 0) == 0) |
| { |
| PUSHs (MPX_NEWMORTAL (z, mpz_class_hv)); |
| } |
| else |
| { |
| free_mpz (z); |
| PUSHs(pv); |
| } |
| |
| |
| mpz |
| overload_copy (z, d1, d2) |
| mpz_assume z |
| dummy d1 |
| dummy d2 |
| CODE: |
| RETVAL = new_mpz(); |
| mpz_set (RETVAL->m, z->m); |
| OUTPUT: |
| RETVAL |
| |
| |
| void |
| DESTROY (z) |
| mpz_assume z |
| CODE: |
| TRACE (printf ("%s DESTROY %p\n", mpz_class, z)); |
| free_mpz (z); |
| |
| |
| malloced_string |
| overload_string (z, d1, d2) |
| mpz_assume z |
| dummy d1 |
| dummy d2 |
| CODE: |
| TRACE (printf ("%s overload_string %p\n", mpz_class, z)); |
| RETVAL = mpz_get_str (NULL, 10, z->m); |
| OUTPUT: |
| RETVAL |
| |
| |
| mpz |
| overload_add (xv, yv, order) |
| SV *xv |
| SV *yv |
| SV *order |
| ALIAS: |
| GMP::Mpz::overload_sub = 1 |
| GMP::Mpz::overload_mul = 2 |
| GMP::Mpz::overload_div = 3 |
| GMP::Mpz::overload_rem = 4 |
| GMP::Mpz::overload_and = 5 |
| GMP::Mpz::overload_ior = 6 |
| GMP::Mpz::overload_xor = 7 |
| PREINIT: |
| static_functable const struct { |
| void (*op) (mpz_ptr, mpz_srcptr, mpz_srcptr); |
| } table[] = { |
| { mpz_add }, /* 0 */ |
| { mpz_sub }, /* 1 */ |
| { mpz_mul }, /* 2 */ |
| { mpz_tdiv_q }, /* 3 */ |
| { mpz_tdiv_r }, /* 4 */ |
| { mpz_and }, /* 5 */ |
| { mpz_ior }, /* 6 */ |
| { mpz_xor }, /* 7 */ |
| }; |
| CODE: |
| assert_table (ix); |
| if (order == &PL_sv_yes) |
| SV_PTR_SWAP (xv, yv); |
| RETVAL = new_mpz(); |
| (*table[ix].op) (RETVAL->m, |
| coerce_mpz (tmp_mpz_0, xv), |
| coerce_mpz (tmp_mpz_1, yv)); |
| OUTPUT: |
| RETVAL |
| |
| |
| void |
| overload_addeq (x, y, o) |
| mpz_assume x |
| mpz_coerce y |
| order_noswap o |
| ALIAS: |
| GMP::Mpz::overload_subeq = 1 |
| GMP::Mpz::overload_muleq = 2 |
| GMP::Mpz::overload_diveq = 3 |
| GMP::Mpz::overload_remeq = 4 |
| GMP::Mpz::overload_andeq = 5 |
| GMP::Mpz::overload_ioreq = 6 |
| GMP::Mpz::overload_xoreq = 7 |
| PREINIT: |
| static_functable const struct { |
| void (*op) (mpz_ptr, mpz_srcptr, mpz_srcptr); |
| } table[] = { |
| { mpz_add }, /* 0 */ |
| { mpz_sub }, /* 1 */ |
| { mpz_mul }, /* 2 */ |
| { mpz_tdiv_q }, /* 3 */ |
| { mpz_tdiv_r }, /* 4 */ |
| { mpz_and }, /* 5 */ |
| { mpz_ior }, /* 6 */ |
| { mpz_xor }, /* 7 */ |
| }; |
| PPCODE: |
| assert_table (ix); |
| (*table[ix].op) (x->m, x->m, y); |
| XPUSHs (ST(0)); |
| |
| |
| mpz |
| overload_lshift (zv, nv, order) |
| SV *zv |
| SV *nv |
| SV *order |
| ALIAS: |
| GMP::Mpz::overload_rshift = 1 |
| GMP::Mpz::overload_pow = 2 |
| PREINIT: |
| static_functable const struct { |
| void (*op) (mpz_ptr, mpz_srcptr, unsigned long); |
| } table[] = { |
| { mpz_mul_2exp }, /* 0 */ |
| { mpz_fdiv_q_2exp }, /* 1 */ |
| { mpz_pow_ui }, /* 2 */ |
| }; |
| CODE: |
| assert_table (ix); |
| if (order == &PL_sv_yes) |
| SV_PTR_SWAP (zv, nv); |
| RETVAL = new_mpz(); |
| (*table[ix].op) (RETVAL->m, coerce_mpz (RETVAL->m, zv), coerce_ulong (nv)); |
| OUTPUT: |
| RETVAL |
| |
| |
| void |
| overload_lshifteq (z, n, o) |
| mpz_assume z |
| ulong_coerce n |
| order_noswap o |
| ALIAS: |
| GMP::Mpz::overload_rshifteq = 1 |
| GMP::Mpz::overload_poweq = 2 |
| PREINIT: |
| static_functable const struct { |
| void (*op) (mpz_ptr, mpz_srcptr, unsigned long); |
| } table[] = { |
| { mpz_mul_2exp }, /* 0 */ |
| { mpz_fdiv_q_2exp }, /* 1 */ |
| { mpz_pow_ui }, /* 2 */ |
| }; |
| PPCODE: |
| assert_table (ix); |
| (*table[ix].op) (z->m, z->m, n); |
| XPUSHs(ST(0)); |
| |
| |
| mpz |
| overload_abs (z, d1, d2) |
| mpz_assume z |
| dummy d1 |
| dummy d2 |
| ALIAS: |
| GMP::Mpz::overload_neg = 1 |
| GMP::Mpz::overload_com = 2 |
| GMP::Mpz::overload_sqrt = 3 |
| PREINIT: |
| static_functable const struct { |
| void (*op) (mpz_ptr w, mpz_srcptr x); |
| } table[] = { |
| { mpz_abs }, /* 0 */ |
| { mpz_neg }, /* 1 */ |
| { mpz_com }, /* 2 */ |
| { mpz_sqrt }, /* 3 */ |
| }; |
| CODE: |
| assert_table (ix); |
| RETVAL = new_mpz(); |
| (*table[ix].op) (RETVAL->m, z->m); |
| OUTPUT: |
| RETVAL |
| |
| |
| void |
| overload_inc (z, d1, d2) |
| mpz_assume z |
| dummy d1 |
| dummy d2 |
| ALIAS: |
| GMP::Mpz::overload_dec = 1 |
| PREINIT: |
| static_functable const struct { |
| void (*op) (mpz_ptr w, mpz_srcptr x, unsigned long y); |
| } table[] = { |
| { mpz_add_ui }, /* 0 */ |
| { mpz_sub_ui }, /* 1 */ |
| }; |
| CODE: |
| assert_table (ix); |
| (*table[ix].op) (z->m, z->m, 1L); |
| |
| |
| int |
| overload_spaceship (xv, yv, order) |
| SV *xv |
| SV *yv |
| SV *order |
| PREINIT: |
| mpz x; |
| CODE: |
| TRACE (printf ("%s overload_spaceship\n", mpz_class)); |
| MPZ_ASSUME (x, xv); |
| switch (use_sv (yv)) { |
| case USE_IVX: |
| RETVAL = mpz_cmp_si (x->m, SvIVX(yv)); |
| break; |
| case USE_UVX: |
| RETVAL = mpz_cmp_ui (x->m, SvUVX(yv)); |
| break; |
| case USE_PVX: |
| RETVAL = mpz_cmp (x->m, coerce_mpz (tmp_mpz_0, yv)); |
| break; |
| case USE_NVX: |
| RETVAL = mpz_cmp_d (x->m, SvNVX(yv)); |
| break; |
| case USE_MPZ: |
| RETVAL = mpz_cmp (x->m, SvMPZ(yv)->m); |
| break; |
| case USE_MPQ: |
| RETVAL = x_mpz_cmp_q (x->m, SvMPQ(yv)->m); |
| break; |
| case USE_MPF: |
| RETVAL = x_mpz_cmp_f (x->m, SvMPF(yv)); |
| break; |
| default: |
| croak ("%s <=>: invalid operand", mpz_class); |
| } |
| RETVAL = SGN (RETVAL); |
| if (order == &PL_sv_yes) |
| RETVAL = -RETVAL; |
| OUTPUT: |
| RETVAL |
| |
| |
| bool |
| overload_bool (z, d1, d2) |
| mpz_assume z |
| dummy d1 |
| dummy d2 |
| ALIAS: |
| GMP::Mpz::overload_not = 1 |
| CODE: |
| RETVAL = (mpz_sgn (z->m) != 0) ^ ix; |
| OUTPUT: |
| RETVAL |
| |
| |
| mpz |
| bin (n, k) |
| mpz_coerce n |
| ulong_coerce k |
| ALIAS: |
| GMP::Mpz::root = 1 |
| PREINIT: |
| /* mpz_root returns an int, hence the cast */ |
| static_functable const struct { |
| void (*op) (mpz_ptr, mpz_srcptr, unsigned long); |
| } table[] = { |
| { mpz_bin_ui }, /* 0 */ |
| { (void (*)(mpz_ptr, mpz_srcptr, unsigned long)) mpz_root }, /* 1 */ |
| }; |
| CODE: |
| assert_table (ix); |
| RETVAL = new_mpz(); |
| (*table[ix].op) (RETVAL->m, n, k); |
| OUTPUT: |
| RETVAL |
| |
| |
| void |
| cdiv (a, d) |
| mpz_coerce a |
| mpz_coerce d |
| ALIAS: |
| GMP::Mpz::fdiv = 1 |
| GMP::Mpz::tdiv = 2 |
| PREINIT: |
| static_functable const struct { |
| void (*op) (mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr); |
| } table[] = { |
| { mpz_cdiv_qr }, /* 0 */ |
| { mpz_fdiv_qr }, /* 1 */ |
| { mpz_tdiv_qr }, /* 2 */ |
| }; |
| mpz q, r; |
| PPCODE: |
| assert_table (ix); |
| q = new_mpz(); |
| r = new_mpz(); |
| (*table[ix].op) (q->m, r->m, a, d); |
| EXTEND (SP, 2); |
| PUSHs (MPX_NEWMORTAL (q, mpz_class_hv)); |
| PUSHs (MPX_NEWMORTAL (r, mpz_class_hv)); |
| |
| |
| void |
| cdiv_2exp (a, d) |
| mpz_coerce a |
| ulong_coerce d |
| ALIAS: |
| GMP::Mpz::fdiv_2exp = 1 |
| GMP::Mpz::tdiv_2exp = 2 |
| PREINIT: |
| static_functable const struct { |
| void (*q) (mpz_ptr, mpz_srcptr, unsigned long); |
| void (*r) (mpz_ptr, mpz_srcptr, unsigned long); |
| } table[] = { |
| { mpz_cdiv_q_2exp, mpz_cdiv_r_2exp }, /* 0 */ |
| { mpz_fdiv_q_2exp, mpz_fdiv_r_2exp }, /* 1 */ |
| { mpz_tdiv_q_2exp, mpz_tdiv_r_2exp }, /* 2 */ |
| }; |
| mpz q, r; |
| PPCODE: |
| assert_table (ix); |
| q = new_mpz(); |
| r = new_mpz(); |
| (*table[ix].q) (q->m, a, d); |
| (*table[ix].r) (r->m, a, d); |
| EXTEND (SP, 2); |
| PUSHs (MPX_NEWMORTAL (q, mpz_class_hv)); |
| PUSHs (MPX_NEWMORTAL (r, mpz_class_hv)); |
| |
| |
| bool |
| congruent_p (a, c, d) |
| mpz_coerce a |
| mpz_coerce c |
| mpz_coerce d |
| PREINIT: |
| CODE: |
| RETVAL = mpz_congruent_p (a, c, d); |
| OUTPUT: |
| RETVAL |
| |
| |
| bool |
| congruent_2exp_p (a, c, d) |
| mpz_coerce a |
| mpz_coerce c |
| ulong_coerce d |
| PREINIT: |
| CODE: |
| RETVAL = mpz_congruent_2exp_p (a, c, d); |
| OUTPUT: |
| RETVAL |
| |
| |
| mpz |
| divexact (a, d) |
| mpz_coerce a |
| mpz_coerce d |
| ALIAS: |
| GMP::Mpz::mod = 1 |
| PREINIT: |
| static_functable const struct { |
| void (*op) (mpz_ptr, mpz_srcptr, mpz_srcptr); |
| } table[] = { |
| { mpz_divexact }, /* 0 */ |
| { mpz_mod }, /* 1 */ |
| }; |
| CODE: |
| assert_table (ix); |
| RETVAL = new_mpz(); |
| (*table[ix].op) (RETVAL->m, a, d); |
| OUTPUT: |
| RETVAL |
| |
| |
| bool |
| divisible_p (a, d) |
| mpz_coerce a |
| mpz_coerce d |
| CODE: |
| RETVAL = mpz_divisible_p (a, d); |
| OUTPUT: |
| RETVAL |
| |
| |
| bool |
| divisible_2exp_p (a, d) |
| mpz_coerce a |
| ulong_coerce d |
| CODE: |
| RETVAL = mpz_divisible_2exp_p (a, d); |
| OUTPUT: |
| RETVAL |
| |
| |
| bool |
| even_p (z) |
| mpz_coerce z |
| ALIAS: |
| GMP::Mpz::odd_p = 1 |
| GMP::Mpz::perfect_square_p = 2 |
| GMP::Mpz::perfect_power_p = 3 |
| PREINIT: |
| static_functable const struct { |
| int (*op) (mpz_srcptr z); |
| } table[] = { |
| { x_mpz_even_p }, /* 0 */ |
| { x_mpz_odd_p }, /* 1 */ |
| { mpz_perfect_square_p }, /* 2 */ |
| { mpz_perfect_power_p }, /* 3 */ |
| }; |
| CODE: |
| assert_table (ix); |
| RETVAL = (*table[ix].op) (z); |
| OUTPUT: |
| RETVAL |
| |
| |
| mpz |
| fac (n) |
| ulong_coerce n |
| ALIAS: |
| GMP::Mpz::fib = 1 |
| GMP::Mpz::lucnum = 2 |
| PREINIT: |
| static_functable const struct { |
| void (*op) (mpz_ptr r, unsigned long n); |
| } table[] = { |
| { mpz_fac_ui }, /* 0 */ |
| { mpz_fib_ui }, /* 1 */ |
| { mpz_lucnum_ui }, /* 2 */ |
| }; |
| CODE: |
| assert_table (ix); |
| RETVAL = new_mpz(); |
| (*table[ix].op) (RETVAL->m, n); |
| OUTPUT: |
| RETVAL |
| |
| |
| void |
| fib2 (n) |
| ulong_coerce n |
| ALIAS: |
| GMP::Mpz::lucnum2 = 1 |
| PREINIT: |
| static_functable const struct { |
| void (*op) (mpz_ptr r, mpz_ptr r2, unsigned long n); |
| } table[] = { |
| { mpz_fib2_ui }, /* 0 */ |
| { mpz_lucnum2_ui }, /* 1 */ |
| }; |
| mpz r, r2; |
| PPCODE: |
| assert_table (ix); |
| r = new_mpz(); |
| r2 = new_mpz(); |
| (*table[ix].op) (r->m, r2->m, n); |
| EXTEND (SP, 2); |
| PUSHs (MPX_NEWMORTAL (r, mpz_class_hv)); |
| PUSHs (MPX_NEWMORTAL (r2, mpz_class_hv)); |
| |
| |
| mpz |
| gcd (x, ...) |
| mpz_coerce x |
| ALIAS: |
| GMP::Mpz::lcm = 1 |
| PREINIT: |
| static_functable const struct { |
| void (*op) (mpz_ptr w, mpz_srcptr x, mpz_srcptr y); |
| void (*op_ui) (mpz_ptr w, mpz_srcptr x, unsigned long y); |
| } table[] = { |
| /* cast to ignore ulong return from mpz_gcd_ui */ |
| { mpz_gcd, |
| (void (*) (mpz_ptr, mpz_srcptr, unsigned long)) mpz_gcd_ui }, /* 0 */ |
| { mpz_lcm, mpz_lcm_ui }, /* 1 */ |
| }; |
| int i; |
| SV *yv; |
| CODE: |
| assert_table (ix); |
| RETVAL = new_mpz(); |
| if (items == 1) |
| mpz_set (RETVAL->m, x); |
| else |
| { |
| for (i = 1; i < items; i++) |
| { |
| yv = ST(i); |
| if (SvIOK(yv)) |
| (*table[ix].op_ui) (RETVAL->m, x, ABS(SvIVX(yv))); |
| else |
| (*table[ix].op) (RETVAL->m, x, coerce_mpz (tmp_mpz_1, yv)); |
| x = RETVAL->m; |
| } |
| } |
| OUTPUT: |
| RETVAL |
| |
| |
| void |
| gcdext (a, b) |
| mpz_coerce a |
| mpz_coerce b |
| PREINIT: |
| mpz g, x, y; |
| SV *sv; |
| PPCODE: |
| g = new_mpz(); |
| x = new_mpz(); |
| y = new_mpz(); |
| mpz_gcdext (g->m, x->m, y->m, a, b); |
| EXTEND (SP, 3); |
| PUSHs (MPX_NEWMORTAL (g, mpz_class_hv)); |
| PUSHs (MPX_NEWMORTAL (x, mpz_class_hv)); |
| PUSHs (MPX_NEWMORTAL (y, mpz_class_hv)); |
| |
| |
| unsigned long |
| hamdist (x, y) |
| mpz_coerce x |
| mpz_coerce y |
| CODE: |
| RETVAL = mpz_hamdist (x, y); |
| OUTPUT: |
| RETVAL |
| |
| |
| mpz |
| invert (a, m) |
| mpz_coerce a |
| mpz_coerce m |
| CODE: |
| RETVAL = new_mpz(); |
| if (! mpz_invert (RETVAL->m, a, m)) |
| { |
| free_mpz (RETVAL); |
| XSRETURN_UNDEF; |
| } |
| OUTPUT: |
| RETVAL |
| |
| |
| int |
| jacobi (a, b) |
| mpz_coerce a |
| mpz_coerce b |
| CODE: |
| RETVAL = mpz_jacobi (a, b); |
| OUTPUT: |
| RETVAL |
| |
| |
| int |
| kronecker (a, b) |
| SV *a |
| SV *b |
| CODE: |
| if (SvIOK(b)) |
| RETVAL = mpz_kronecker_si (coerce_mpz(tmp_mpz_0,a), SvIVX(b)); |
| else if (SvIOK(a)) |
| RETVAL = mpz_si_kronecker (SvIVX(a), coerce_mpz(tmp_mpz_0,b)); |
| else |
| RETVAL = mpz_kronecker (coerce_mpz(tmp_mpz_0,a), |
| coerce_mpz(tmp_mpz_1,b)); |
| OUTPUT: |
| RETVAL |
| |
| |
| void |
| mpz_export (order, size, endian, nails, z) |
| int order |
| size_t size |
| int endian |
| size_t nails |
| mpz_coerce z |
| PREINIT: |
| size_t numb, count, bytes, actual_count; |
| char *data; |
| SV *sv; |
| PPCODE: |
| numb = 8*size - nails; |
| count = (mpz_sizeinbase (z, 2) + numb-1) / numb; |
| bytes = count * size; |
| New (GMP_MALLOC_ID, data, bytes+1, char); |
| mpz_export (data, &actual_count, order, size, endian, nails, z); |
| assert (count == actual_count); |
| data[bytes] = '\0'; |
| sv = sv_newmortal(); sv_usepvn_mg (sv, data, bytes); PUSHs(sv); |
| |
| |
| mpz |
| mpz_import (order, size, endian, nails, sv) |
| int order |
| size_t size |
| int endian |
| size_t nails |
| SV *sv |
| PREINIT: |
| size_t count; |
| const char *data; |
| STRLEN len; |
| CODE: |
| data = SvPV (sv, len); |
| if ((len % size) != 0) |
| croak ("%s mpz_import: string not a multiple of the given size", |
| mpz_class); |
| count = len / size; |
| RETVAL = new_mpz(); |
| mpz_import (RETVAL->m, count, order, size, endian, nails, data); |
| OUTPUT: |
| RETVAL |
| |
| |
| mpz |
| nextprime (z) |
| mpz_coerce z |
| CODE: |
| RETVAL = new_mpz(); |
| mpz_nextprime (RETVAL->m, z); |
| OUTPUT: |
| RETVAL |
| |
| |
| unsigned long |
| popcount (x) |
| mpz_coerce x |
| CODE: |
| RETVAL = mpz_popcount (x); |
| OUTPUT: |
| RETVAL |
| |
| |
| mpz |
| powm (b, e, m) |
| mpz_coerce b |
| mpz_coerce e |
| mpz_coerce m |
| CODE: |
| RETVAL = new_mpz(); |
| mpz_powm (RETVAL->m, b, e, m); |
| OUTPUT: |
| RETVAL |
| |
| |
| bool |
| probab_prime_p (z, n) |
| mpz_coerce z |
| ulong_coerce n |
| CODE: |
| RETVAL = mpz_probab_prime_p (z, n); |
| OUTPUT: |
| RETVAL |
| |
| |
| # No attempt to coerce here, only an mpz makes sense. |
| void |
| realloc (z, limbs) |
| mpz z |
| int limbs |
| CODE: |
| _mpz_realloc (z->m, limbs); |
| |
| |
| void |
| remove (z, f) |
| mpz_coerce z |
| mpz_coerce f |
| PREINIT: |
| SV *sv; |
| mpz rem; |
| unsigned long mult; |
| PPCODE: |
| rem = new_mpz(); |
| mult = mpz_remove (rem->m, z, f); |
| EXTEND (SP, 2); |
| PUSHs (MPX_NEWMORTAL (rem, mpz_class_hv)); |
| PUSHs (sv_2mortal (newSViv (mult))); |
| |
| |
| void |
| roote (z, n) |
| mpz_coerce z |
| ulong_coerce n |
| PREINIT: |
| SV *sv; |
| mpz root; |
| int exact; |
| PPCODE: |
| root = new_mpz(); |
| exact = mpz_root (root->m, z, n); |
| EXTEND (SP, 2); |
| PUSHs (MPX_NEWMORTAL (root, mpz_class_hv)); |
| sv = (exact ? &PL_sv_yes : &PL_sv_no); sv_2mortal(sv); PUSHs(sv); |
| |
| |
| void |
| rootrem (z, n) |
| mpz_coerce z |
| ulong_coerce n |
| PREINIT: |
| SV *sv; |
| mpz root; |
| mpz rem; |
| PPCODE: |
| root = new_mpz(); |
| rem = new_mpz(); |
| mpz_rootrem (root->m, rem->m, z, n); |
| EXTEND (SP, 2); |
| PUSHs (MPX_NEWMORTAL (root, mpz_class_hv)); |
| PUSHs (MPX_NEWMORTAL (rem, mpz_class_hv)); |
| |
| |
| # In the past scan0 and scan1 were described as returning ULONG_MAX which |
| # could be obtained in perl with ~0. That wasn't true on 64-bit systems |
| # (eg. alpha) with perl 5.005, since in that version IV and UV were still |
| # 32-bits. |
| # |
| # We changed in gmp 4.2 to just say ~0 for the not-found return. It's |
| # likely most people have used ~0 rather than POSIX::ULONG_MAX(), so this |
| # change should match existing usage. It only actually makes a difference |
| # in old perl, since recent versions have gone to 64-bits for IV and UV, the |
| # same as a ulong. |
| # |
| # In perl 5.005 we explicitly mask the mpz return down to 32-bits to get ~0. |
| # UV_MAX is no good, it reflects the size of the UV type (64-bits), rather |
| # than the size of the values one ought to be storing in an SV (32-bits). |
| |
| gmp_UV |
| scan0 (z, start) |
| mpz_coerce z |
| ulong_coerce start |
| ALIAS: |
| GMP::Mpz::scan1 = 1 |
| PREINIT: |
| static_functable const struct { |
| unsigned long (*op) (mpz_srcptr, unsigned long); |
| } table[] = { |
| { mpz_scan0 }, /* 0 */ |
| { mpz_scan1 }, /* 1 */ |
| }; |
| CODE: |
| assert_table (ix); |
| RETVAL = (*table[ix].op) (z, start); |
| if (PERL_LT (5,6)) |
| RETVAL &= 0xFFFFFFFF; |
| OUTPUT: |
| RETVAL |
| |
| |
| void |
| setbit (sv, bit) |
| SV *sv |
| ulong_coerce bit |
| ALIAS: |
| GMP::Mpz::clrbit = 1 |
| GMP::Mpz::combit = 2 |
| PREINIT: |
| static_functable const struct { |
| void (*op) (mpz_ptr, unsigned long); |
| } table[] = { |
| { mpz_setbit }, /* 0 */ |
| { mpz_clrbit }, /* 1 */ |
| { mpz_combit }, /* 2 */ |
| }; |
| int use; |
| mpz z; |
| CODE: |
| use = use_sv (sv); |
| if (use == USE_MPZ && SvREFCNT(SvRV(sv)) == 1 && ! SvSMAGICAL(sv)) |
| { |
| /* our operand is a non-magical mpz with a reference count of 1, so |
| we can just modify it */ |
| (*table[ix].op) (SvMPZ(sv)->m, bit); |
| } |
| else |
| { |
| /* otherwise we need to make a new mpz, from whatever we have, and |
| operate on that, possibly invoking magic when storing back */ |
| SV *new_sv; |
| mpz z = new_mpz (); |
| mpz_ptr coerce_ptr = coerce_mpz_using (z->m, sv, use); |
| if (coerce_ptr != z->m) |
| mpz_set (z->m, coerce_ptr); |
| (*table[ix].op) (z->m, bit); |
| new_sv = sv_bless (sv_setref_pv (sv_newmortal(), NULL, z), |
| mpz_class_hv); |
| SvSetMagicSV (sv, new_sv); |
| } |
| |
| |
| void |
| sqrtrem (z) |
| mpz_coerce z |
| PREINIT: |
| SV *sv; |
| mpz root; |
| mpz rem; |
| PPCODE: |
| root = new_mpz(); |
| rem = new_mpz(); |
| mpz_sqrtrem (root->m, rem->m, z); |
| EXTEND (SP, 2); |
| PUSHs (MPX_NEWMORTAL (root, mpz_class_hv)); |
| PUSHs (MPX_NEWMORTAL (rem, mpz_class_hv)); |
| |
| |
| size_t |
| sizeinbase (z, base) |
| mpz_coerce z |
| int base |
| CODE: |
| RETVAL = mpz_sizeinbase (z, base); |
| OUTPUT: |
| RETVAL |
| |
| |
| int |
| tstbit (z, bit) |
| mpz_coerce z |
| ulong_coerce bit |
| CODE: |
| RETVAL = mpz_tstbit (z, bit); |
| OUTPUT: |
| RETVAL |
| |
| |
| |
| #------------------------------------------------------------------------------ |
| |
| MODULE = GMP PACKAGE = GMP::Mpq |
| |
| |
| mpq |
| mpq (...) |
| ALIAS: |
| GMP::Mpq::new = 1 |
| CODE: |
| TRACE (printf ("%s new, ix=%ld, items=%d\n", mpq_class, ix, (int) items)); |
| RETVAL = new_mpq(); |
| switch (items) { |
| case 0: |
| mpq_set_ui (RETVAL->m, 0L, 1L); |
| break; |
| case 1: |
| { |
| mpq_ptr rp = RETVAL->m; |
| mpq_ptr cp = coerce_mpq (rp, ST(0)); |
| if (cp != rp) |
| mpq_set (rp, cp); |
| } |
| break; |
| case 2: |
| { |
| mpz_ptr rp, cp; |
| rp = mpq_numref (RETVAL->m); |
| cp = coerce_mpz (rp, ST(0)); |
| if (cp != rp) |
| mpz_set (rp, cp); |
| rp = mpq_denref (RETVAL->m); |
| cp = coerce_mpz (rp, ST(1)); |
| if (cp != rp) |
| mpz_set (rp, cp); |
| } |
| break; |
| default: |
| croak ("%s new: invalid arguments", mpq_class); |
| } |
| OUTPUT: |
| RETVAL |
| |
| |
| void |
| overload_constant (str, pv, d1, ...) |
| const_string_assume str |
| SV *pv |
| dummy d1 |
| PREINIT: |
| SV *sv; |
| mpq q; |
| PPCODE: |
| TRACE (printf ("%s constant: %s\n", mpq_class, str)); |
| q = new_mpq(); |
| if (mpq_set_str (q->m, str, 0) == 0) |
| { sv = sv_bless (sv_setref_pv (sv_newmortal(), NULL, q), mpq_class_hv); } |
| else |
| { free_mpq (q); sv = pv; } |
| XPUSHs(sv); |
| |
| |
| mpq |
| overload_copy (q, d1, d2) |
| mpq_assume q |
| dummy d1 |
| dummy d2 |
| CODE: |
| RETVAL = new_mpq(); |
| mpq_set (RETVAL->m, q->m); |
| OUTPUT: |
| RETVAL |
| |
| |
| void |
| DESTROY (q) |
| mpq_assume q |
| CODE: |
| TRACE (printf ("%s DESTROY %p\n", mpq_class, q)); |
| free_mpq (q); |
| |
| |
| malloced_string |
| overload_string (q, d1, d2) |
| mpq_assume q |
| dummy d1 |
| dummy d2 |
| CODE: |
| TRACE (printf ("%s overload_string %p\n", mpq_class, q)); |
| RETVAL = mpq_get_str (NULL, 10, q->m); |
| OUTPUT: |
| RETVAL |
| |
| |
| mpq |
| overload_add (xv, yv, order) |
| SV *xv |
| SV *yv |
| SV *order |
| ALIAS: |
| GMP::Mpq::overload_sub = 1 |
| GMP::Mpq::overload_mul = 2 |
| GMP::Mpq::overload_div = 3 |
| PREINIT: |
| static_functable const struct { |
| void (*op) (mpq_ptr, mpq_srcptr, mpq_srcptr); |
| } table[] = { |
| { mpq_add }, /* 0 */ |
| { mpq_sub }, /* 1 */ |
| { mpq_mul }, /* 2 */ |
| { mpq_div }, /* 3 */ |
| }; |
| CODE: |
| TRACE (printf ("%s binary\n", mpf_class)); |
| assert_table (ix); |
| if (order == &PL_sv_yes) |
| SV_PTR_SWAP (xv, yv); |
| RETVAL = new_mpq(); |
| (*table[ix].op) (RETVAL->m, |
| coerce_mpq (tmp_mpq_0, xv), |
| coerce_mpq (tmp_mpq_1, yv)); |
| OUTPUT: |
| RETVAL |
| |
| |
| void |
| overload_addeq (x, y, o) |
| mpq_assume x |
| mpq_coerce y |
| order_noswap o |
| ALIAS: |
| GMP::Mpq::overload_subeq = 1 |
| GMP::Mpq::overload_muleq = 2 |
| GMP::Mpq::overload_diveq = 3 |
| PREINIT: |
| static_functable const struct { |
| void (*op) (mpq_ptr, mpq_srcptr, mpq_srcptr); |
| } table[] = { |
| { mpq_add }, /* 0 */ |
| { mpq_sub }, /* 1 */ |
| { mpq_mul }, /* 2 */ |
| { mpq_div }, /* 3 */ |
| }; |
| PPCODE: |
| assert_table (ix); |
| (*table[ix].op) (x->m, x->m, y); |
| XPUSHs(ST(0)); |
| |
| |
| mpq |
| overload_lshift (qv, nv, order) |
| SV *qv |
| SV *nv |
| SV *order |
| ALIAS: |
| GMP::Mpq::overload_rshift = 1 |
| GMP::Mpq::overload_pow = 2 |
| PREINIT: |
| static_functable const struct { |
| void (*op) (mpq_ptr, mpq_srcptr, unsigned long); |
| } table[] = { |
| { mpq_mul_2exp }, /* 0 */ |
| { mpq_div_2exp }, /* 1 */ |
| { x_mpq_pow_ui }, /* 2 */ |
| }; |
| CODE: |
| assert_table (ix); |
| if (order == &PL_sv_yes) |
| SV_PTR_SWAP (qv, nv); |
| RETVAL = new_mpq(); |
| (*table[ix].op) (RETVAL->m, coerce_mpq (RETVAL->m, qv), coerce_ulong (nv)); |
| OUTPUT: |
| RETVAL |
| |
| |
| void |
| overload_lshifteq (q, n, o) |
| mpq_assume q |
| ulong_coerce n |
| order_noswap o |
| ALIAS: |
| GMP::Mpq::overload_rshifteq = 1 |
| GMP::Mpq::overload_poweq = 2 |
| PREINIT: |
| static_functable const struct { |
| void (*op) (mpq_ptr, mpq_srcptr, unsigned long); |
| } table[] = { |
| { mpq_mul_2exp }, /* 0 */ |
| { mpq_div_2exp }, /* 1 */ |
| { x_mpq_pow_ui }, /* 2 */ |
| }; |
| PPCODE: |
| assert_table (ix); |
| (*table[ix].op) (q->m, q->m, n); |
| XPUSHs(ST(0)); |
| |
| |
| void |
| overload_inc (q, d1, d2) |
| mpq_assume q |
| dummy d1 |
| dummy d2 |
| ALIAS: |
| GMP::Mpq::overload_dec = 1 |
| PREINIT: |
| static_functable const struct { |
| void (*op) (mpz_ptr, mpz_srcptr, mpz_srcptr); |
| } table[] = { |
| { mpz_add }, /* 0 */ |
| { mpz_sub }, /* 1 */ |
| }; |
| CODE: |
| assert_table (ix); |
| (*table[ix].op) (mpq_numref(q->m), mpq_numref(q->m), mpq_denref(q->m)); |
| |
| |
| mpq |
| overload_abs (q, d1, d2) |
| mpq_assume q |
| dummy d1 |
| dummy d2 |
| ALIAS: |
| GMP::Mpq::overload_neg = 1 |
| PREINIT: |
| static_functable const struct { |
| void (*op) (mpq_ptr w, mpq_srcptr x); |
| } table[] = { |
| { mpq_abs }, /* 0 */ |
| { mpq_neg }, /* 1 */ |
| }; |
| CODE: |
| assert_table (ix); |
| RETVAL = new_mpq(); |
| (*table[ix].op) (RETVAL->m, q->m); |
| OUTPUT: |
| RETVAL |
| |
| |
| int |
| overload_spaceship (x, y, order) |
| mpq_assume x |
| mpq_coerce y |
| SV *order |
| CODE: |
| RETVAL = mpq_cmp (x->m, y); |
| RETVAL = SGN (RETVAL); |
| if (order == &PL_sv_yes) |
| RETVAL = -RETVAL; |
| OUTPUT: |
| RETVAL |
| |
| |
| bool |
| overload_bool (q, d1, d2) |
| mpq_assume q |
| dummy d1 |
| dummy d2 |
| ALIAS: |
| GMP::Mpq::overload_not = 1 |
| CODE: |
| RETVAL = (mpq_sgn (q->m) != 0) ^ ix; |
| OUTPUT: |
| RETVAL |
| |
| |
| bool |
| overload_eq (x, yv, d) |
| mpq_assume x |
| SV *yv |
| dummy d |
| ALIAS: |
| GMP::Mpq::overload_ne = 1 |
| PREINIT: |
| int use; |
| CODE: |
| use = use_sv (yv); |
| switch (use) { |
| case USE_IVX: |
| case USE_UVX: |
| case USE_MPZ: |
| RETVAL = 0; |
| if (x_mpq_integer_p (x->m)) |
| { |
| switch (use) { |
| case USE_IVX: |
| RETVAL = (mpz_cmp_si (mpq_numref(x->m), SvIVX(yv)) == 0); |
| break; |
| case USE_UVX: |
| RETVAL = (mpz_cmp_ui (mpq_numref(x->m), SvUVX(yv)) == 0); |
| break; |
| case USE_MPZ: |
| RETVAL = (mpz_cmp (mpq_numref(x->m), SvMPZ(yv)->m) == 0); |
| break; |
| } |
| } |
| break; |
| |
| case USE_MPQ: |
| RETVAL = (mpq_equal (x->m, SvMPQ(yv)->m) != 0); |
| break; |
| |
| default: |
| RETVAL = (mpq_equal (x->m, coerce_mpq_using (tmp_mpq_0, yv, use)) != 0); |
| break; |
| } |
| RETVAL ^= ix; |
| OUTPUT: |
| RETVAL |
| |
| |
| void |
| canonicalize (q) |
| mpq q |
| CODE: |
| mpq_canonicalize (q->m); |
| |
| |
| mpq |
| inv (q) |
| mpq_coerce q |
| CODE: |
| RETVAL = new_mpq(); |
| mpq_inv (RETVAL->m, q); |
| OUTPUT: |
| RETVAL |
| |
| |
| mpz |
| num (q) |
| mpq q |
| ALIAS: |
| GMP::Mpq::den = 1 |
| CODE: |
| RETVAL = new_mpz(); |
| mpz_set (RETVAL->m, (ix == 0 ? mpq_numref(q->m) : mpq_denref(q->m))); |
| OUTPUT: |
| RETVAL |
| |
| |
| |
| #------------------------------------------------------------------------------ |
| |
| MODULE = GMP PACKAGE = GMP::Mpf |
| |
| |
| mpf |
| mpf (...) |
| ALIAS: |
| GMP::Mpf::new = 1 |
| PREINIT: |
| unsigned long prec; |
| CODE: |
| TRACE (printf ("%s new\n", mpf_class)); |
| if (items > 2) |
| croak ("%s new: invalid arguments", mpf_class); |
| prec = (items == 2 ? coerce_ulong (ST(1)) : mpf_get_default_prec()); |
| RETVAL = new_mpf (prec); |
| if (items >= 1) |
| { |
| SV *sv = ST(0); |
| my_mpf_set_sv_using (RETVAL, sv, use_sv(sv)); |
| } |
| OUTPUT: |
| RETVAL |
| |
| |
| mpf |
| overload_constant (sv, d1, d2, ...) |
| SV *sv |
| dummy d1 |
| dummy d2 |
| CODE: |
| assert (SvPOK (sv)); |
| TRACE (printf ("%s constant: %s\n", mpq_class, SvPVX(sv))); |
| RETVAL = new_mpf (mpf_get_default_prec()); |
| my_mpf_set_svstr (RETVAL, sv); |
| OUTPUT: |
| RETVAL |
| |
| |
| mpf |
| overload_copy (f, d1, d2) |
| mpf_assume f |
| dummy d1 |
| dummy d2 |
| CODE: |
| TRACE (printf ("%s copy\n", mpf_class)); |
| RETVAL = new_mpf (mpf_get_prec (f)); |
| mpf_set (RETVAL, f); |
| OUTPUT: |
| RETVAL |
| |
| |
| void |
| DESTROY (f) |
| mpf_assume f |
| CODE: |
| TRACE (printf ("%s DESTROY %p\n", mpf_class, f)); |
| mpf_clear (f); |
| Safefree (f); |
| assert_support (mpf_count--); |
| TRACE_ACTIVE (); |
| |
| |
| mpf |
| overload_add (x, y, order) |
| mpf_assume x |
| mpf_coerce_st0 y |
| SV *order |
| ALIAS: |
| GMP::Mpf::overload_sub = 1 |
| GMP::Mpf::overload_mul = 2 |
| GMP::Mpf::overload_div = 3 |
| PREINIT: |
| static_functable const struct { |
| void (*op) (mpf_ptr, mpf_srcptr, mpf_srcptr); |
| } table[] = { |
| { mpf_add }, /* 0 */ |
| { mpf_sub }, /* 1 */ |
| { mpf_mul }, /* 2 */ |
| { mpf_div }, /* 3 */ |
| }; |
| CODE: |
| assert_table (ix); |
| RETVAL = new_mpf (mpf_get_prec (x)); |
| if (order == &PL_sv_yes) |
| MPF_PTR_SWAP (x, y); |
| (*table[ix].op) (RETVAL, x, y); |
| OUTPUT: |
| RETVAL |
| |
| |
| void |
| overload_addeq (x, y, o) |
| mpf_assume x |
| mpf_coerce_st0 y |
| order_noswap o |
| ALIAS: |
| GMP::Mpf::overload_subeq = 1 |
| GMP::Mpf::overload_muleq = 2 |
| GMP::Mpf::overload_diveq = 3 |
| PREINIT: |
| static_functable const struct { |
| void (*op) (mpf_ptr, mpf_srcptr, mpf_srcptr); |
| } table[] = { |
| { mpf_add }, /* 0 */ |
| { mpf_sub }, /* 1 */ |
| { mpf_mul }, /* 2 */ |
| { mpf_div }, /* 3 */ |
| }; |
| PPCODE: |
| assert_table (ix); |
| (*table[ix].op) (x, x, y); |
| XPUSHs(ST(0)); |
| |
| |
| mpf |
| overload_lshift (fv, nv, order) |
| SV *fv |
| SV *nv |
| SV *order |
| ALIAS: |
| GMP::Mpf::overload_rshift = 1 |
| GMP::Mpf::overload_pow = 2 |
| PREINIT: |
| static_functable const struct { |
| void (*op) (mpf_ptr, mpf_srcptr, unsigned long); |
| } table[] = { |
| { mpf_mul_2exp }, /* 0 */ |
| { mpf_div_2exp }, /* 1 */ |
| { mpf_pow_ui }, /* 2 */ |
| }; |
| mpf f; |
| unsigned long prec; |
| CODE: |
| assert_table (ix); |
| MPF_ASSUME (f, fv); |
| prec = mpf_get_prec (f); |
| if (order == &PL_sv_yes) |
| SV_PTR_SWAP (fv, nv); |
| f = coerce_mpf (tmp_mpf_0, fv, prec); |
| RETVAL = new_mpf (prec); |
| (*table[ix].op) (RETVAL, f, coerce_ulong (nv)); |
| OUTPUT: |
| RETVAL |
| |
| |
| void |
| overload_lshifteq (f, n, o) |
| mpf_assume f |
| ulong_coerce n |
| order_noswap o |
| ALIAS: |
| GMP::Mpf::overload_rshifteq = 1 |
| GMP::Mpf::overload_poweq = 2 |
| PREINIT: |
| static_functable const struct { |
| void (*op) (mpf_ptr, mpf_srcptr, unsigned long); |
| } table[] = { |
| { mpf_mul_2exp }, /* 0 */ |
| { mpf_div_2exp }, /* 1 */ |
| { mpf_pow_ui }, /* 2 */ |
| }; |
| PPCODE: |
| assert_table (ix); |
| (*table[ix].op) (f, f, n); |
| XPUSHs(ST(0)); |
| |
| |
| mpf |
| overload_abs (f, d1, d2) |
| mpf_assume f |
| dummy d1 |
| dummy d2 |
| ALIAS: |
| GMP::Mpf::overload_neg = 1 |
| GMP::Mpf::overload_sqrt = 2 |
| PREINIT: |
| static_functable const struct { |
| void (*op) (mpf_ptr w, mpf_srcptr x); |
| } table[] = { |
| { mpf_abs }, /* 0 */ |
| { mpf_neg }, /* 1 */ |
| { mpf_sqrt }, /* 2 */ |
| }; |
| CODE: |
| assert_table (ix); |
| RETVAL = new_mpf (mpf_get_prec (f)); |
| (*table[ix].op) (RETVAL, f); |
| OUTPUT: |
| RETVAL |
| |
| |
| void |
| overload_inc (f, d1, d2) |
| mpf_assume f |
| dummy d1 |
| dummy d2 |
| ALIAS: |
| GMP::Mpf::overload_dec = 1 |
| PREINIT: |
| static_functable const struct { |
| void (*op) (mpf_ptr w, mpf_srcptr x, unsigned long y); |
| } table[] = { |
| { mpf_add_ui }, /* 0 */ |
| { mpf_sub_ui }, /* 1 */ |
| }; |
| CODE: |
| assert_table (ix); |
| (*table[ix].op) (f, f, 1L); |
| |
| |
| int |
| overload_spaceship (xv, yv, order) |
| SV *xv |
| SV *yv |
| SV *order |
| PREINIT: |
| mpf x; |
| CODE: |
| MPF_ASSUME (x, xv); |
| switch (use_sv (yv)) { |
| case USE_IVX: |
| RETVAL = mpf_cmp_si (x, SvIVX(yv)); |
| break; |
| case USE_UVX: |
| RETVAL = mpf_cmp_ui (x, SvUVX(yv)); |
| break; |
| case USE_NVX: |
| RETVAL = mpf_cmp_d (x, SvNVX(yv)); |
| break; |
| case USE_PVX: |
| { |
| STRLEN len; |
| const char *str = SvPV (yv, len); |
| /* enough for all digits of the string */ |
| tmp_mpf_set_prec (tmp_mpf_0, strlen(str)+64); |
| if (mpf_set_str (tmp_mpf_0->m, str, 10) != 0) |
| croak ("%s <=>: invalid string format", mpf_class); |
| RETVAL = mpf_cmp (x, tmp_mpf_0->m); |
| } |
| break; |
| case USE_MPZ: |
| RETVAL = - x_mpz_cmp_f (SvMPZ(yv)->m, x); |
| break; |
| case USE_MPF: |
| RETVAL = mpf_cmp (x, SvMPF(yv)); |
| break; |
| default: |
| RETVAL = mpq_cmp (coerce_mpq (tmp_mpq_0, xv), |
| coerce_mpq (tmp_mpq_1, yv)); |
| break; |
| } |
| RETVAL = SGN (RETVAL); |
| if (order == &PL_sv_yes) |
| RETVAL = -RETVAL; |
| OUTPUT: |
| RETVAL |
| |
| |
| bool |
| overload_bool (f, d1, d2) |
| mpf_assume f |
| dummy d1 |
| dummy d2 |
| ALIAS: |
| GMP::Mpf::overload_not = 1 |
| CODE: |
| RETVAL = (mpf_sgn (f) != 0) ^ ix; |
| OUTPUT: |
| RETVAL |
| |
| |
| mpf |
| ceil (f) |
| mpf_coerce_def f |
| ALIAS: |
| GMP::Mpf::floor = 1 |
| GMP::Mpf::trunc = 2 |
| PREINIT: |
| static_functable const struct { |
| void (*op) (mpf_ptr w, mpf_srcptr x); |
| } table[] = { |
| { mpf_ceil }, /* 0 */ |
| { mpf_floor }, /* 1 */ |
| { mpf_trunc }, /* 2 */ |
| }; |
| CODE: |
| assert_table (ix); |
| RETVAL = new_mpf (mpf_get_prec (f)); |
| (*table[ix].op) (RETVAL, f); |
| OUTPUT: |
| RETVAL |
| |
| |
| unsigned long |
| get_default_prec () |
| CODE: |
| RETVAL = mpf_get_default_prec(); |
| OUTPUT: |
| RETVAL |
| |
| |
| unsigned long |
| get_prec (f) |
| mpf_coerce_def f |
| CODE: |
| RETVAL = mpf_get_prec (f); |
| OUTPUT: |
| RETVAL |
| |
| |
| bool |
| mpf_eq (xv, yv, bits) |
| SV *xv |
| SV *yv |
| ulong_coerce bits |
| PREINIT: |
| mpf x, y; |
| CODE: |
| TRACE (printf ("%s eq\n", mpf_class)); |
| coerce_mpf_pair (&x,xv, &y,yv); |
| RETVAL = mpf_eq (x, y, bits); |
| OUTPUT: |
| RETVAL |
| |
| |
| mpf |
| reldiff (xv, yv) |
| SV *xv |
| SV *yv |
| PREINIT: |
| mpf x, y; |
| unsigned long prec; |
| CODE: |
| TRACE (printf ("%s reldiff\n", mpf_class)); |
| prec = coerce_mpf_pair (&x,xv, &y,yv); |
| RETVAL = new_mpf (prec); |
| mpf_reldiff (RETVAL, x, y); |
| OUTPUT: |
| RETVAL |
| |
| |
| void |
| set_default_prec (prec) |
| ulong_coerce prec |
| CODE: |
| TRACE (printf ("%s set_default_prec %lu\n", mpf_class, prec)); |
| mpf_set_default_prec (prec); |
| |
| |
| void |
| set_prec (sv, prec) |
| SV *sv |
| ulong_coerce prec |
| PREINIT: |
| mpf_ptr old_f, new_f; |
| int use; |
| CODE: |
| TRACE (printf ("%s set_prec to %lu\n", mpf_class, prec)); |
| use = use_sv (sv); |
| if (use == USE_MPF) |
| { |
| old_f = SvMPF(sv); |
| if (SvREFCNT(SvRV(sv)) == 1) |
| mpf_set_prec (old_f, prec); |
| else |
| { |
| TRACE (printf (" fork new mpf\n")); |
| new_f = new_mpf (prec); |
| mpf_set (new_f, old_f); |
| goto setref; |
| } |
| } |
| else |
| { |
| TRACE (printf (" coerce to mpf\n")); |
| new_f = new_mpf (prec); |
| my_mpf_set_sv_using (new_f, sv, use); |
| setref: |
| sv_bless (sv_setref_pv (sv, NULL, new_f), mpf_class_hv); |
| } |
| |
| |
| |
| #------------------------------------------------------------------------------ |
| |
| MODULE = GMP PACKAGE = GMP::Rand |
| |
| randstate |
| new (...) |
| ALIAS: |
| GMP::Rand::randstate = 1 |
| CODE: |
| TRACE (printf ("%s new\n", rand_class)); |
| New (GMP_MALLOC_ID, RETVAL, 1, __gmp_randstate_struct); |
| TRACE (printf (" RETVAL %p\n", RETVAL)); |
| assert_support (rand_count++); |
| TRACE_ACTIVE (); |
| |
| if (items == 0) |
| { |
| gmp_randinit_default (RETVAL); |
| } |
| else |
| { |
| if (SvROK (ST(0)) && sv_derived_from (ST(0), rand_class)) |
| { |
| if (items != 1) |
| goto invalid; |
| gmp_randinit_set (RETVAL, SvRANDSTATE (ST(0))); |
| } |
| else |
| { |
| STRLEN len; |
| const char *method = SvPV (ST(0), len); |
| assert (len == strlen (method)); |
| if (strcmp (method, "lc_2exp") == 0) |
| { |
| if (items != 4) |
| goto invalid; |
| gmp_randinit_lc_2exp (RETVAL, |
| coerce_mpz (tmp_mpz_0, ST(1)), |
| coerce_ulong (ST(2)), |
| coerce_ulong (ST(3))); |
| } |
| else if (strcmp (method, "lc_2exp_size") == 0) |
| { |
| if (items != 2) |
| goto invalid; |
| if (! gmp_randinit_lc_2exp_size (RETVAL, coerce_ulong (ST(1)))) |
| { |
| Safefree (RETVAL); |
| XSRETURN_UNDEF; |
| } |
| } |
| else if (strcmp (method, "mt") == 0) |
| { |
| if (items != 1) |
| goto invalid; |
| gmp_randinit_mt (RETVAL); |
| } |
| else |
| { |
| invalid: |
| croak ("%s new: invalid arguments", rand_class); |
| } |
| } |
| } |
| OUTPUT: |
| RETVAL |
| |
| |
| void |
| DESTROY (r) |
| randstate r |
| CODE: |
| TRACE (printf ("%s DESTROY\n", rand_class)); |
| gmp_randclear (r); |
| Safefree (r); |
| assert_support (rand_count--); |
| TRACE_ACTIVE (); |
| |
| |
| void |
| seed (r, z) |
| randstate r |
| mpz_coerce z |
| CODE: |
| gmp_randseed (r, z); |
| |
| |
| mpz |
| mpz_urandomb (r, bits) |
| randstate r |
| ulong_coerce bits |
| ALIAS: |
| GMP::Rand::mpz_rrandomb = 1 |
| PREINIT: |
| static_functable const struct { |
| void (*fun) (mpz_ptr, gmp_randstate_t r, unsigned long bits); |
| } table[] = { |
| { mpz_urandomb }, /* 0 */ |
| { mpz_rrandomb }, /* 1 */ |
| }; |
| CODE: |
| assert_table (ix); |
| RETVAL = new_mpz(); |
| (*table[ix].fun) (RETVAL->m, r, bits); |
| OUTPUT: |
| RETVAL |
| |
| |
| mpz |
| mpz_urandomm (r, m) |
| randstate r |
| mpz_coerce m |
| CODE: |
| RETVAL = new_mpz(); |
| mpz_urandomm (RETVAL->m, r, m); |
| OUTPUT: |
| RETVAL |
| |
| |
| mpf |
| mpf_urandomb (r, bits) |
| randstate r |
| ulong_coerce bits |
| CODE: |
| RETVAL = new_mpf (bits); |
| mpf_urandomb (RETVAL, r, bits); |
| OUTPUT: |
| RETVAL |
| |
| |
| unsigned long |
| gmp_urandomb_ui (r, bits) |
| randstate r |
| ulong_coerce bits |
| ALIAS: |
| GMP::Rand::gmp_urandomm_ui = 1 |
| PREINIT: |
| static_functable const struct { |
| unsigned long (*fun) (gmp_randstate_t r, unsigned long bits); |
| } table[] = { |
| { gmp_urandomb_ui }, /* 0 */ |
| { gmp_urandomm_ui }, /* 1 */ |
| }; |
| CODE: |
| assert_table (ix); |
| RETVAL = (*table[ix].fun) (r, bits); |
| OUTPUT: |
| RETVAL |