[BACK]Return to GMP.xs CVS log [TXT][DIR] Up to [local] / OpenXM_contrib / gmp / demos / perl

Annotation of OpenXM_contrib/gmp/demos/perl/GMP.xs, Revision 1.1.1.1

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>