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