Math-Prime-Util-GMP
view release on metacpan or search on metacpan
PROTOTYPES: ENABLE
void _GMP_init()
void _GMP_destroy()
void _GMP_memfree()
void _GMP_set_verbose(IN int v)
PPCODE:
set_verbose_level(v);
void seed_csprng(IN UV bytes, IN unsigned char* seed)
PPCODE:
isaac_init(bytes, seed);
UV irand()
ALIAS:
irand64 = 1
is_csprng_well_seeded = 2
CODE:
switch (ix) {
#if BITS_PER_WORD >= 64
case 0: RETVAL = isaac_rand32(); break;
RETVAL = is_miller_prime(n, assumegrh);
mpz_clear(n);
OUTPUT:
RETVAL
void
_is_provable_prime(IN char* strn, IN int wantproof = 0)
PREINIT:
int result;
mpz_t n;
PPCODE:
PRIMALITY_START("is_provable_prime", 2, 1);
if (wantproof == 0) {
result = _GMP_is_provable_prime(n, 0);
XPUSH_INT(result);
} else {
char* prooftext = 0;
result = _GMP_is_provable_prime(n, &prooftext);
XPUSH_INT(result);
if (prooftext) {
XPUSHs(sv_2mortal(newSVpv(prooftext, 0)));
OUTPUT:
RETVAL
void
next_prime(IN char* strn)
ALIAS:
prev_prime = 1
next_twin_prime = 2
PREINIT:
mpz_t n;
PPCODE:
validate_and_set(n, IFLAG_NONNEG);
if (ix == 1 && mpz_cmp_ui(n,3) < 0) { mpz_clear(n); XSRETURN_UNDEF; }
if (ix == 0) _GMP_next_prime(n);
else if (ix == 1) _GMP_prev_prime(n);
else next_twin_prime(n, n);
XPUSH_MPZ(n);
mpz_clear(n);
void
random_prime(IN char* strlo, IN char* strhi = 0)
PREINIT:
mpz_t lo, hi, res;
int retundef;
PPCODE:
if (items == 1) {
validate_and_set(lo, IFLAG_NONNEG);
mpz_init_set(hi, lo);
mpz_set_ui(lo,0);
} else {
validate_and_set(lo, IFLAG_NONNEG);
validate_and_set(hi, IFLAG_NONNEG);
}
mpz_init(res);
retundef = !mpz_random_prime(res, lo, hi);
if (!retundef) XPUSH_MPZ(res);
mpz_clear(res); mpz_clear(hi); mpz_clear(lo);
if (retundef) XSRETURN_UNDEF;
void
urandomr(IN char* strlo, IN char* strhi)
PREINIT:
mpz_t lo, hi, res;
PPCODE:
validate_and_set(lo, IFLAG_ANY);
validate_and_set(hi, IFLAG_ANY);
if (mpz_cmp(lo,hi) > 0) {
mpz_clear(lo); mpz_clear(hi);
XSRETURN_UNDEF;
}
if (mpz_sgn(lo) >= 0 && mpz_sgn(hi) >= 0 && mpz_sizeinbase(hi,2) <= 32) {
uint32_t ulo = mpz_get_ui(lo), uhi = mpz_get_ui(hi);
if (uhi - ulo < UINT32_MAX) {
mpz_clear(lo); mpz_clear(hi);
mpz_add(res,res,lo);
XPUSH_MPZ(res);
mpz_clear(res); mpz_clear(hi); mpz_clear(lo);
void prime_count(IN char* strlo, IN char* strhi = 0)
ALIAS:
prime_power_count = 1
perfect_power_count = 2
PREINIT:
mpz_t lo, hi, res;
PPCODE:
mpz_init(res);
if (items == 1) {
validate_and_set(lo, IFLAG_NONNEG);
switch (ix) {
case 0: prime_count(res, lo); break;
case 1: prime_power_count(res, lo); break;
case 2: perfect_power_count(res, lo); break;
default: break;
}
mpz_clear(lo);
}
mpz_clear(lo);
mpz_clear(hi);
}
XPUSH_MPZ(res);
mpz_clear(res);
void legendre_phi(IN char* strn, IN char* stra)
PREINIT:
mpz_t n, a, res;
PPCODE:
validate_and_set(n, IFLAG_NONNEG);
validate_and_set(a, IFLAG_NONNEG);
mpz_init(res);
legendre_phi(res, n, a);
XPUSH_MPZ(res);
mpz_clear(res);
mpz_clear(a);
mpz_clear(n);
void nth_perfect_power(IN char* strn)
ALIAS:
nth_perfect_power_approx = 1
PREINIT:
mpz_t n, res;
PPCODE:
validate_and_set(n, IFLAG_NONNEG);
mpz_init(res);
if (ix == 0) nth_perfect_power(res, n);
else nth_perfect_power_approx(res, n);
XPUSH_MPZ(res);
mpz_clear(n);
mpz_clear(res);
void next_perfect_power(IN char* strn)
ALIAS:
prev_perfect_power = 1
PREINIT:
mpz_t n, res;
PPCODE:
validate_and_set(n, IFLAG_ANY);
mpz_init(res);
if (ix == 0) next_perfect_power(res, n);
else prev_perfect_power(res, n);
XPUSH_MPZ(res);
mpz_clear(n);
mpz_clear(res);
void totient(IN char* strn)
ALIAS:
carmichael_lambda = 1
ramanujan_tau = 2
sqrtint = 3
prime_count_lower = 4
prime_count_upper = 5
PREINIT:
mpz_t n;
PPCODE:
validate_and_set(n, IFLAG_NONNEG);
switch (ix) {
case 0: totient(n, n); break;
case 1: carmichael_lambda(n, n); break;
case 2: rtau(n, n); break;
case 3: mpz_sqrt(n, n); break;
case 4: prime_count_lower(n, n); break;
case 5: prime_count_upper(n, n); break;
default: break;
}
XPUSH_MPZ(n);
mpz_clear(n);
void absint(IN char* strn)
PREINIT:
mpz_t n;
PPCODE:
validate_and_set(n, IFLAG_ABS);
XPUSH_MPZ(n);
mpz_clear(n);
void urandomm(IN char* strn)
PREINIT:
mpz_t n;
PPCODE:
validate_and_set(n, IFLAG_NONNEG);
mpz_isaac_urandomm(n, n);
XPUSH_MPZ(n);
mpz_clear(n);
void is_prime_power(IN char* strn)
PREINIT:
mpz_t n;
UV R;
PPCODE:
validate_and_set(n, IFLAG_ANY);
R = (mpz_sgn(n) <= 0) ? 0 : prime_power(n, n);
mpz_clear(n);
XSRETURN_UV(R);
void signint(IN char* strn)
PREINIT:
mpz_t n;
int res;
PPCODE:
validate_and_set(n, IFLAG_ANY);
res = mpz_sgn(n);
mpz_clear(n);
XSRETURN_IV(res);
void cmpint(IN char* stra, IN char* strb)
ALIAS:
cmpabsint = 1
PREINIT:
mpz_t a, b;
int res;
PPCODE:
validate_and_set(a, IFLAG_ANY);
validate_and_set(b, IFLAG_ANY);
res = (ix == 0) ? mpz_cmp(a, b) : mpz_cmpabs(a, b);
/* GMP 6.2 changed to only return -1,0,1 */
/* Enforce -1, 0, 1 as our only return values. */
if (res < 0) res = -1;
if (res > 0) res = 1;
mpz_clear(a);
mpz_clear(b);
XSRETURN_IV(res);
void setbit(IN char* strn, IN UV k)
ALIAS:
clrbit = 1
notbit = 2
tstbit = 3
PREINIT:
mpz_t n;
int res;
PPCODE:
validate_and_set(n, IFLAG_ANY);
switch (ix) {
case 0: mpz_setbit(n, k); break;
case 1: mpz_clrbit(n, k); break;
case 2: mpz_combit(n, k); break;
case 3: res = mpz_tstbit(n, k); break;
default: break;
}
if (ix != 3) XPUSH_MPZ(n);
mpz_clear(n);
if (ix == 3) XSRETURN_IV(res);
void bitand(IN char* stra, IN char* strb)
ALIAS:
bitor = 1
bitxor = 2
PREINIT:
mpz_t a, b;
PPCODE:
validate_and_set(a, IFLAG_ANY);
validate_and_set(b, IFLAG_ANY);
switch (ix) {
case 0: mpz_and(a, a, b); break;
case 1: mpz_ior(a, a, b); break;
case 2: mpz_xor(a, a, b); break;
default: break;
}
XPUSH_MPZ(a);
mpz_clear(a);
mpz_clear(b);
void bitnot(IN char* strn)
ALIAS:
negint = 1
add1int = 2
sub1int = 3
exp_mangoldt = 4
PREINIT:
mpz_t n;
PPCODE:
validate_and_set(n, IFLAG_ANY);
switch (ix) {
case 0: mpz_com(n, n); break;
case 1: mpz_neg(n, n); break;
case 2: mpz_add_ui(n, n, 1); break;
case 3: mpz_sub_ui(n, n, 1); break;
case 4: exp_mangoldt(n, n); break;
default: break;
}
XPUSH_MPZ(n);
mpz_clear(n);
void bernfrac(IN char* strn)
ALIAS:
harmfrac = 1
PREINIT:
mpz_t n, d;
PPCODE:
validate_and_set(n, IFLAG_NONNEG);
mpz_init(d);
if (ix == 0) bernfrac(n,d,n);
else harmfrac(n,d,n);
XPUSH_MPZ(n);
XPUSH_MPZ(d);
mpz_clear(d);
mpz_clear(n);
void harmreal(IN char* strn, IN UV prec = 40)
zeta = 4
li = 5
ei = 6
riemannr = 7
lambertw = 8
surround_primes = 9
PREINIT:
mpz_t n;
mpf_t f;
char* res;
PPCODE:
if (ix == 9) { /* surround_primes */
UV prev, next;
validate_and_set(n, IFLAG_NONNEG);
next = 1 + (mpz_sgn(n)==0);
if (mpz_cmp_ui(n,2) > 0) {
surround_primes(n, &prev, &next, (items == 1) ? 0 : prec);
XPUSH_UINT(prev);
} else {
XPUSHs(sv_2mortal(newSV(0)));
}
rootreal = 1
agmreal = 2
addreal = 3
subreal = 4
mulreal = 5
divreal = 6
PREINIT:
mpf_t n, x;
char* res;
unsigned long bits, bits2, bits3;
PPCODE:
bits = 64 + (unsigned long)(3.32193 * prec);
bits2 = 64 + (unsigned long)(3.32193 * strlen(strn));
bits3 = 64 + (unsigned long)(3.32193 * strlen(strx));
if (bits2 > bits) bits = bits2;
if (bits3 > bits) bits = bits3;
mpf_init2(n, bits);
if (mpf_set_str(n, strn, 10) != 0)
croak("Not valid base-10 floating point input: %s", strn);
mpf_init2(x, bits);
if (mpf_set_str(x, strx, 10) != 0)
mpf_clear(x);
if (res == 0)
XSRETURN_UNDEF;
XPUSHs(sv_2mortal(newSVpv(res, 0)));
Safefree(res);
void bernvec(IN UV n)
PREINIT:
const mpz_t *N, *D;
UV i;
PPCODE:
bernvec(&N, &D, n); /* Cached array, do not destroy */
if (GIMME_V != G_VOID) {
EXTEND(SP, (long)(n+1));
for (i = 0; i <= n; i++) {
AV* av = newAV();
av_push(av, sv_return_for_mpz(aTHX_ N[i]));
av_push(av, sv_return_for_mpz(aTHX_ D[i]));
PUSHs( sv_2mortal(newRV_noinc( (SV*) av )) );
}
}
void
gcd(...)
PROTOTYPE: @
ALIAS:
lcm = 1
vecsum = 2
vecprod = 3
PREINIT:
int i, negflag;
mpz_t ret, n;
PPCODE:
if (items == 0) XSRETURN_IV( (ix == 1 || ix == 3) ? 1 : 0);
negflag = (ix <= 1) ? IFLAG_ABS : IFLAG_ANY;
if (ix == 1 || ix == 3) {
mpz_t* list;
New(0, list, items, mpz_t);
for (i = 0; i < items; i++) {
char* strn = SvPV_nolen(ST(i));
set_integer_string(list[i], "arg", strn, negflag);
}
if (ix == 1) mpz_veclcm(list, 0, items-1);
void
vecprefixsum(...)
PROTOTYPE: @
PREINIT:
AV *av;
SV *sv;
SV **svp;
int plen;
size_t i, len;
mpz_t sum, n;
PPCODE:
av = 0;
plen = -1;
if (items > 0 && SvROK(ST(0)) && SvTYPE(SvRV(ST(0))) == SVt_PVAV) {
if (items != 1)
croak("vecprefixsum: expected integer list or single array reference");
av = (AV*) SvRV(ST(0));
plen = av_len(av);
len = (plen < 0) ? 0 : (size_t)plen + 1;
} else {
len = (size_t)items;
mpz_clear(b);
mpz_clear(a);
OUTPUT:
RETVAL
void remove_factors(IN char* strn, IN char* strk)
ALIAS:
remove_factors_exp = 1
PREINIT:
mpz_t n, k;
PPCODE:
validate_and_set(n, IFLAG_ANY);
validate_and_set(k, IFLAG_NONNEG);
if (mpz_cmp_ui(k,2) < 0) {
mpz_clear(k); mpz_clear(n);
croak("%s: k must be > 1", SUBNAME);
}
if (mpz_sgn(n) == 0) {
XPUSHs(&PL_sv_undef);
if (ix == 1) XPUSHs(&PL_sv_undef);
} else {
UV e = mpz_remove(n, n, k);
XPUSH_MPZ(n);
if (ix == 1) XPUSH_UINT(e);
}
mpz_clear(k);
mpz_clear(n);
void moebius(IN char* strn, IN char* strnhi = 0)
PREINIT:
mpz_t n, nhi;
PPCODE:
validate_and_set(n, IFLAG_ANY);
if (items == 1) {
XPUSH_INT(moebius(n));
} else {
validate_and_set(nhi, IFLAG_ANY);
if (GIMME_V != G_ARRAY) {
if (mpz_cmp(n,nhi) > 0) { mpz_set_ui(n,0); }
else { mpz_sub(nhi,nhi,n); mpz_add_ui(n,nhi,1); }
XPUSH_MPZ(n);
} else {
mpz_add_ui(n, n, 1);
}
}
mpz_clear(nhi);
}
mpz_clear(n);
void euler_phi(IN char* strn, IN char* strnhi = 0)
PREINIT:
mpz_t n, nhi, r;
PPCODE:
validate_and_set(n, IFLAG_ANY);
if (items == 1) {
totient(n, n);
XPUSH_MPZ(n);
} else {
validate_and_set(nhi, IFLAG_ANY);
if (GIMME_V != G_ARRAY) {
if (mpz_cmp(n,nhi) > 0) { mpz_set_ui(n,0); }
else { mpz_sub(nhi,nhi,n); mpz_add_ui(n,nhi,1); }
XPUSH_MPZ(n);
mpz_clear(nhi);
}
mpz_clear(n);
void lucasu(IN char* strp, IN char* strq, IN char* strk)
ALIAS:
lucasv = 1
lucasuv = 2
PREINIT:
mpz_t u, v, p, q, k;
PPCODE:
validate_and_set(p, IFLAG_ANY);
validate_and_set(q, IFLAG_ANY);
validate_and_set(k, IFLAG_NONNEG);
mpz_init(u); mpz_init(v);
lucasuv(u, v, p, q, k);
switch (ix) {
case 0: XPUSH_MPZ(u); break;
case 1: XPUSH_MPZ(v); break;
case 2:
default: XPUSH_MPZ(u); XPUSH_MPZ(v); break;
}
mpz_clear(v); mpz_clear(u);
mpz_clear(k); mpz_clear(q); mpz_clear(p);
void lucasumod(IN char* strp, IN char* strq, IN char* strk, IN char* strn)
ALIAS:
lucasvmod = 1
lucasuvmod = 2
PREINIT:
mpz_t u, v, t, p, q, k, n;
PPCODE:
validate_and_set(p, IFLAG_ANY);
validate_and_set(q, IFLAG_ANY);
validate_and_set(k, IFLAG_NONNEG);
validate_and_set(n, IFLAG_ABS);
if (mpz_cmpabs_ui(n,1) <= 0) {
int retundef = (mpz_sgn(n) == 0);
mpz_clear(n); mpz_clear(k); mpz_clear(q); mpz_clear(p);
if (retundef) XSRETURN_UNDEF;
else if (ix != 2) XSRETURN_IV(0);
else { XPUSH_UINT(0); XPUSH_UINT(0); XSRETURN(2); }
}
if (ix == 0 || ix == 2) mpz_clear(u);
if (ix == 1 || ix == 2) mpz_clear(v);
mpz_clear(t);
mpz_clear(n); mpz_clear(k); mpz_clear(q); mpz_clear(p);
void catalan_number(IN char* strn)
PREINIT:
mpz_t n;
unsigned long un;
PPCODE:
validate_and_set(n, IFLAG_NONNEG);
if (!mpz_fits_ulong_p(n))
croak("catalan_number: argument too large");
un = mpz_get_ui(n);
if (un <= 1) {
mpz_set_ui(n, 1);
} else {
mpz_mul_2exp(n, n, 1); /* n = 2*un as mpz */
mpz_bin_ui(n, n, un); /* C(2un, un) */
mpz_divexact_ui(n, n, un+1); /* / (un+1) */
}
XPUSH_MPZ(n);
mpz_clear(n);
void bell_number(IN char* strn)
PREINIT:
mpz_t n;
PPCODE:
validate_and_set(n, IFLAG_NONNEG);
if (!mpz_fits_ulong_p(n))
croak("bell_number: argument too large");
bell_number(n, mpz_get_ui(n));
XPUSH_MPZ(n);
mpz_clear(n);
void fubini(IN char* strn)
PREINIT:
mpz_t n;
PPCODE:
validate_and_set(n, IFLAG_NONNEG);
if (!mpz_fits_ulong_p(n))
croak("fubini: argument too large");
fubini(n, mpz_get_ui(n));
XPUSH_MPZ(n);
mpz_clear(n);
void fibonacci(IN char* strk)
ALIAS:
lucas_number = 1
PREINIT:
mpz_t k;
unsigned long uk;
int isneg;
PPCODE:
isneg = validate_and_set(k, IFLAG_ABS);
if (!mpz_fits_ulong_p(k))
croak("%s: argument too large", GvNAME(CvGV(cv)));
uk = mpz_get_ui(k);
if (ix == 0) {
mpz_fib_ui(k, uk);
if (isneg && (uk & 1) == 0) mpz_neg(k, k); /* F(-n) = -F(n) if n even */
} else {
mpz_lucnum_ui(k, uk);
if (isneg && (uk & 1) == 1) mpz_neg(k, k); /* L(-n) = -L(n) if n odd */
void
sopf(IN char* strn)
ALIAS:
sopfr = 1
dedekind_psi = 2
aliquot_sum = 3
abundance = 4
PREINIT:
mpz_t n;
PPCODE:
validate_and_set(n, ix == 2 ? IFLAG_ANY : IFLAG_NONNEG);
switch (ix) {
case 0: sopf(n, n); break;
case 1: sopfr(n, n); break;
case 2: dedekind_psi(n, n); break;
case 3: aliquot_sum(n, n); break;
case 4: abundance(n, n); break;
default: break;
}
XPUSH_MPZ(n);
mpz_clear(n);
void
prime_signature(IN char* strn)
PREINIT:
mpz_t n, r;
uint32_t *signature;
int i, nsig;
PPCODE:
validate_and_set(n, IFLAG_NONNEG);
if (GIMME_V == G_ARRAY) {
nsig = prime_signature(0, &signature, n);
EXTEND(SP, nsig);
for (i = 0; i < nsig; i++)
XPUSH_UINT(signature[i]);
if (signature != 0) Safefree(signature);
} else {
mpz_init(r);
prime_signature(r, 0, n);
RETVAL
void
next_powerfree(IN char* strn, IN UV k = 2)
ALIAS:
prev_powerfree = 1
nth_powerfree = 2
PREINIT:
mpz_t n;
int retundef;
PPCODE:
validate_and_set(n, IFLAG_NONNEG);
switch (ix) {
case 0: next_powerfree(n,n,k); break;
case 1: prev_powerfree(n,n,k); break;
case 2: nth_powerfree(n,n,k); break;
default: break;
}
retundef = (mpz_sgn(n) <= 0);
if (!retundef) XPUSH_MPZ(n);
mpz_clear(n);
powint = 3
divint = 4
modint = 5
cdivint = 6
divrem = 7
tdivrem = 8
fdivrem = 9
cdivrem = 10
PREINIT:
mpz_t a, b;
PPCODE:
validate_and_set(a, IFLAG_ANY);
validate_and_set(b, IFLAG_ANY);
if (ix >= 4 && mpz_sgn(b) == 0)
croak("%s: divide by zero", SUBNAME);
switch (ix) {
case 0: mpz_add(a, a, b); break;
case 1: mpz_sub(a, a, b); break;
case 2: mpz_mul(a, a, b); break;
case 3: if (mpz_sgn(b) < 0)
croak("powint: exponent must be non-negative");
case 10:mpz_cdiv_qr(b, a, a, b); break;
default:break;
}
if (ix >= 7) XPUSH_MPZ(b);
XPUSH_MPZ(a);
mpz_clear(b); mpz_clear(a);
void rootint(IN char* strn, IN char* strk)
PREINIT:
mpz_t n, k;
PPCODE:
validate_and_set(n, IFLAG_NONNEG);
validate_and_set(k, IFLAG_POS);
mpz_rootint(n, n, k);
XPUSH_MPZ(n);
mpz_clear(n); mpz_clear(k);
void logint(IN char* strn, IN char* strb)
PREINIT:
mpz_t n, b;
PPCODE:
validate_and_set(n, IFLAG_POS);
validate_and_set(b, IFLAG_POS);
if (mpz_cmp_ui(b,2) < 0) croak("logint: base must be at least 2");
mpz_logint(n, n, b);
XPUSH_MPZ(n);
mpz_clear(n); mpz_clear(b);
void invmod(IN char* stra, IN char* strn)
ALIAS:
negmod = 1
sqrtmod = 2
factorialmod = 3
znorder = 4
is_qr = 5
is_primitive_root = 6
PREINIT:
mpz_t a, n;
int retundef;
PPCODE:
validate_and_set(a, IFLAG_ANY);
validate_and_set(n, IFLAG_ABS);
if (mpz_sgn(n) == 0) {
mpz_clear(n); mpz_clear(a);
XSRETURN_UNDEF;
}
if (mpz_cmp_ui(n,1) == 0) {
mpz_clear(n); mpz_clear(a);
XSRETURN_UV(ix >= 4 ? 1 : 0);
}
if (retundef) {
mpz_clear(n); mpz_clear(a);
XSRETURN_UNDEF;
}
XPUSH_MPZ(a);
mpz_clear(n); mpz_clear(a);
void znprimroot(IN char* strn)
PREINIT:
mpz_t n;
PPCODE:
validate_and_set(n, IFLAG_ABS);
znprimroot(n, n);
if (mpz_sgn(n) < 0)
{ mpz_clear(n); XSRETURN_UNDEF; }
XPUSH_MPZ(n);
mpz_clear(n);
void znlog(IN char* stra, IN char* strg, IN char* strn)
PREINIT:
mpz_t a, g, n, r;
int ok;
PPCODE:
validate_and_set(a, IFLAG_ANY);
validate_and_set(g, IFLAG_ANY);
validate_and_set(n, IFLAG_ABS);
mpz_init(r);
ok = _GMP_znlog(r, a, g, n);
if (ok) XPUSH_MPZ(r);
mpz_clear(r); mpz_clear(n); mpz_clear(g); mpz_clear(a);
if (!ok) XSRETURN_UNDEF;
void multifactorial(IN char* strn, IN char* strm)
PREINIT:
mpz_t n, m;
PPCODE:
validate_and_set(n, IFLAG_NONNEG);
validate_and_set(m, IFLAG_POS);
mpz_mfac(n, n, m);
XPUSH_MPZ(n);
mpz_clear(m); mpz_clear(n);
void is_polygonal(IN char* stra, IN char* strb)
ALIAS:
polygonal_nth = 1
PREINIT:
mpz_t a, b;
PPCODE:
validate_and_set(a, IFLAG_ANY);
validate_and_set(b, IFLAG_NONNEG);
if (mpz_cmp_ui(b,3) < 0) croak("%s: k must be >= 3",SUBNAME);
polygonal_nth(a, a, b);
if (ix == 0) {
int ret = mpz_sgn(a) > 0;
mpz_clear(b); mpz_clear(a);
XSRETURN_IV(ret);
}
XPUSH_MPZ(a);
mpz_clear(b); mpz_clear(a);
void binomial(IN char* stra, IN char* strb)
PREINIT:
mpz_t a, b;
unsigned long n, k;
PPCODE:
validate_and_set(a, IFLAG_ANY);
validate_and_set(b, IFLAG_ANY);
if (mpz_sgn(a) >= 0) {
int reflect = 0;
if (mpz_sgn(b) < 0 || mpz_cmp(b,a) > 0)
{ mpz_clear(a); mpz_clear(b); XSRETURN_IV(0); }
/* Check reflection to possibly reduce b */
mpz_mul_2exp(b,b,1);
reflect = mpz_cmp(b,a) > 0;
mpz_tdiv_q_2exp(b,b,1);
else mpz_bin_uiui(a, n, k);
} else {
mpz_bin_ui(a, a, k);
}
XPUSH_MPZ(a);
mpz_clear(b); mpz_clear(a);
void gcdext(IN char* stra, IN char* strb)
PREINIT:
mpz_t a, b, t;
PPCODE:
validate_and_set(a, IFLAG_ANY);
validate_and_set(b, IFLAG_ANY);
mpz_init(t);
if (mpz_sgn(a) == 0 && mpz_sgn(b) == 0) {
mpz_set_ui(t, 0); /* This changed in GMP 5.1.2. Enforce new result. */
} else {
gcdext(a, t, b, a, b);
}
XPUSH_MPZ(t); XPUSH_MPZ(b); XPUSH_MPZ(a);
mpz_clear(t); mpz_clear(b); mpz_clear(a);
void muladdint(IN char* stra, IN char* strb, IN char* strc)
ALIAS:
mulsubint = 1
addmulint = 2
submulint = 3
PREINIT:
mpz_t a, b, c;
PPCODE:
validate_and_set(a, IFLAG_ANY);
validate_and_set(b, IFLAG_ANY);
validate_and_set(c, IFLAG_ANY);
if (ix == 0) { mpz_mul(a, a, b); mpz_add(a, a, c); } /* a * b + c */
else if (ix == 1) { mpz_mul(a, a, b); mpz_sub(a, a, c); } /* a * b - c */
else if (ix == 2) { mpz_addmul(a, b, c); } /* a + b * c */
else { mpz_submul(a, b, c); } /* a - b * c */
XPUSH_MPZ(a);
mpz_clear(c); mpz_clear(b); mpz_clear(a);
void
binomialmod(IN char* strn, IN char* strk, IN char* strm)
PREINIT:
mpz_t n, k, m;
PPCODE:
validate_and_set(n, IFLAG_ANY);
validate_and_set(k, IFLAG_ANY);
validate_and_set(m, IFLAG_ABS);
if (mpz_sgn(m) == 0) {
mpz_clear(n); mpz_clear(k); mpz_clear(m);
XSRETURN_UNDEF;
}
binomialmod(n, n, k, m);
XPUSH_MPZ(n);
mpz_clear(m);
mpz_clear(k);
mpz_clear(n);
void
falling_factorial(IN char* strx, IN char* strn)
ALIAS:
rising_factorial = 1
PREINIT:
mpz_t x, n, r;
PPCODE:
validate_and_set(x, IFLAG_ANY);
validate_and_set(n, IFLAG_NONNEG);
mpz_init(r);
if (ix == 0) falling_factorial(r, x, n);
else rising_factorial(r, x, n);
mpz_clear(x);
mpz_clear(n);
XPUSH_MPZ(r);
mpz_clear(r);
void powersum(IN char* stra, IN char* strb)
ALIAS:
faulhaber_sum = 1
jordan_totient = 2
PREINIT:
mpz_t a, b;
PPCODE:
validate_and_set(a, IFLAG_NONNEG);
validate_and_set(b, IFLAG_NONNEG);
if (ix == 0 || ix == 1) {
if (!mpz_fits_ulong_p(b)) croak("%s: power too large", SUBNAME);
faulhaber_sum(a, a, mpz_get_ui(b));
} else {
if (!mpz_fits_ulong_p(a)) croak("%s: power too large", SUBNAME);
jordan_totient(a, b, mpz_get_ui(a));
}
XPUSH_MPZ(a);
mpz_clear(b); mpz_clear(a);
void
lshiftint(IN char* strn, IN long k = 1)
ALIAS:
rshiftint = 1
rashiftint = 2
PREINIT:
mpz_t n;
int nix;
PPCODE:
validate_and_set(n, IFLAG_ANY);
nix = ix;
if (k < 0) {
k = -k;
nix = !nix; /* left => right, right or arith_right => left */
}
switch (nix) {
case 0: mpz_mul_2exp(n, n, k); break;
case 1: mpz_tdiv_q_2exp(n, n, k); break;
case 2:
}
XPUSH_MPZ(n);
mpz_clear(n);
void
powerful_count(IN char* strn, IN int k = 2)
ALIAS:
powerfree_count = 1
PREINIT:
mpz_t n, r;
PPCODE:
validate_and_set(n, IFLAG_ANY);
mpz_init(r);
switch (ix) {
case 0: powerful_count(r, n, (unsigned long) k); break;
case 1: powerfree_count(r, n, (uint32_t) k); break;
default: break;
}
XPUSH_MPZ(r);
mpz_clear(r);
mpz_clear(n);
addmod(IN char* stra, IN char* strb, IN char* strn)
ALIAS:
submod = 1
mulmod = 2
powmod = 3
divmod = 4
rootmod = 5
PREINIT:
mpz_t a, b, n;
int retundef;
PPCODE:
validate_and_set(a, IFLAG_ANY);
validate_and_set(b, IFLAG_ANY);
validate_and_set(n, IFLAG_ABS);
retundef = (mpz_sgn(n) <= 0);
if (!retundef && ix == 4) {
if (mpz_cmp_ui(n,1) > 0) { /* if n is 1, let the mod turn it into zero */
mpz_mod(b, b, n); /* Get b between 0 and n-1. */
if (mpz_sgn(b) == 0) retundef = 1;
else if (mpz_cmp_ui(b,1) > 0) retundef = !mpz_invert(b,b,n);
}
XSRETURN_UNDEF;
}
XPUSH_MPZ(a);
mpz_clear(n); mpz_clear(b); mpz_clear(a);
void allsqrtmod(IN char* stra, IN char* strn)
PREINIT:
mpz_t a, n;
mpz_t *roots;
UV i, nroots;
PPCODE:
validate_and_set(a, IFLAG_ANY);
validate_and_set(n, IFLAG_ABS);
if (mpz_sgn(n) == 0) {
mpz_clear(n); mpz_clear(a);
if (GIMME_V == G_ARRAY) XSRETURN_EMPTY;
XSRETURN_UV(0);
}
if (GIMME_V != G_ARRAY) {
nroots = allsqrtmod_count(a, n);
mpz_clear(n); mpz_clear(a);
for (i = 0; i < nroots; i++)
XPUSH_MPZ(roots[i]);
clear_rootmod_list(roots, nroots);
mpz_clear(n); mpz_clear(a);
void allrootmod(IN char* stra, IN char* strk, IN char* strn)
PREINIT:
mpz_t a, k, n;
mpz_t *roots;
UV i, nroots;
PPCODE:
validate_and_set(a, IFLAG_ANY);
validate_and_set(k, IFLAG_ANY);
validate_and_set(n, IFLAG_ABS);
if (mpz_sgn(n) == 0) {
mpz_clear(n); mpz_clear(k); mpz_clear(a);
if (GIMME_V == G_ARRAY) XSRETURN_EMPTY;
XSRETURN_UV(0);
}
if (GIMME_V != G_ARRAY) {
nroots = allrootmod_count(a, k, n);
for (i = 0; i < nroots; i++)
XPUSH_MPZ(roots[i]);
clear_rootmod_list(roots, nroots);
mpz_clear(n); mpz_clear(k); mpz_clear(a);
void muladdmod(IN char* stra, IN char* strb, IN char* strc, IN char* strn)
ALIAS:
mulsubmod = 1
PREINIT:
mpz_t a, b, c, n;
PPCODE:
validate_and_set(a, IFLAG_ANY);
validate_and_set(b, IFLAG_ANY);
validate_and_set(c, IFLAG_ANY);
validate_and_set(n, IFLAG_ABS);
if (mpz_sgn(n) <= 0) {
mpz_clear(n); mpz_clear(c); mpz_clear(b); mpz_clear(a);
XSRETURN_UNDEF;
}
mpz_mul(a,a,b);
if (ix == 0) mpz_add(a, a, c);
RETVAL = lucas_lehmer(n);
OUTPUT:
RETVAL
void Pi(IN UV n)
ALIAS:
Euler = 1
random_bytes = 2
PREINIT:
UV prec;
PPCODE:
if (ix == 2) { /* random_bytes */
char* sptr;
SV* sv = newSV(n == 0 ? 1 : n);
SvPOK_only(sv);
SvCUR_set(sv, n);
sptr = SvPVX(sv);
isaac_rand_bytes(n, (unsigned char*)sptr);
sptr[n] = '\0';
PUSHs(sv_2mortal(sv));
XSRETURN(1);
subfactorial = 11
partitions = 12
partitionsq = 13
primorial = 14
pn_primorial = 15
consecutive_integer_lcm = 16
PREINIT:
mpz_t p, N;
UV n;
char* proof;
PPCODE:
validate_and_set(N, IFLAG_NONNEG);
if (!mpz_fits_uv_p(N))
{ mpz_clear(N); croak("%s: argument too large",SUBNAME); }
n = mpz_get_uv(N);
mpz_clear(N);
if (ix == 8 && n <= BITS_PER_WORD) {
UV v = irand64(n);
ST(0) = sv_2mortal(newSVuv(v));
XSRETURN(1);
}
if (proof) {
XPUSHs(sv_2mortal(newSVpv(proof, 0)));
Safefree(proof);
}
void
stirling(IN char* strn, IN char* strm, IN char* strtype = 0)
PREINIT:
mpz_t n, m, type;
int stype = 1;
PPCODE:
validate_and_set(n, IFLAG_NONNEG);
validate_and_set(m, IFLAG_NONNEG);
if (items > 2) {
validate_and_set(type, IFLAG_ANY);
stype = mpz_fits_sint_p(type) ? (int)mpz_get_si(type) : 0;
mpz_clear(type);
}
mpz_stirling(n, n, m, stype);
XPUSH_MPZ(n);
mpz_clear(m);
mpz_clear(n);
void chinese(...)
ALIAS:
chinese2 = 1
PROTOTYPE: @
PREINIT:
int i, doretval;
mpz_t* an;
mpz_t ret, lcm;
PPCODE:
if (items == 0) {
if (ix == 0) XSRETURN_IV(0);
XPUSH_UINT(0);
XPUSH_UINT(0);
XSRETURN(2);
}
mpz_init_set_ui(ret, 0);
New(0, an, 2*items, mpz_t);
for (i = 0; i < items; i++) {
AV* av;
}
void
permtonum(SV* svp)
PREINIT:
AV *av;
char* seen;
UV val, *V;
int plen, n, i, j, k;
mpz_t f, t, num;
PPCODE:
if ((!SvROK(svp)) || (SvTYPE(SvRV(svp)) != SVt_PVAV))
croak("permtonum argument must be an array reference");
av = (AV*) SvRV(svp);
plen = av_len(av);
if (plen < 0) XSRETURN_IV(0);
Newz(0, seen, plen+1, char);
New(0, V, plen+1, UV);
for (i = 0; i <= plen; i++) {
SV **iv = av_fetch(av, i, 0);
if (iv == 0) break;
mpz_divexact_ui(f, f, n-i-1);
}
Safefree(V);
XPUSH_MPZ(num);
mpz_clear(num); mpz_clear(t); mpz_clear(f);
void numtoperm(IN UV n, IN char* strk)
PREINIT:
mpz_t k, f, p;
UV i, j, tv, *perm;
PPCODE:
if (n == 0)
XSRETURN_EMPTY;
validate_and_set(k, IFLAG_ANY);
mpz_init(f); mpz_init(p);
New(0, perm, n, UV);
for (i = 0; i < n; i++)
perm[i] = i;
mpz_fac_ui(f, n);
mpz_mod(k,k,f);
for (i = 0; i < n-1; i++) {
mpz_clear(p); mpz_clear(f); mpz_clear(k);
void
sieve_prime_cluster(IN char* strlow, IN char* strhigh, ...)
ALIAS:
sieve_primes = 1
sieve_twin_primes = 2
PREINIT:
mpz_t low, seghigh, high, t;
UV i, nc, nprimes, maxseg, *list;
PPCODE:
validate_and_set(low, IFLAG_NONNEG);
validate_and_set(high, IFLAG_NONNEG);
mpz_init(seghigh);
mpz_init_set_ui(t,0);
nc = items-1;
maxseg = ((UV_MAX > ULONG_MAX) ? ULONG_MAX : UV_MAX);
/* Loop as needed */
while (mpz_cmp(low, high) <= 0) {
mpz_clear(low);
void
primes(IN SV* svlo, IN SV* svhi = 0)
ALIAS:
twin_primes = 1
PREINIT:
AV* av;
mpz_t low, seghigh, high, t;
UV i, nprimes, maxseg, *list;
PPCODE:
if (!SvOK(svlo) || (items >= 2 && !SvOK(svhi)))
croak("Parameter must be defined");
if (items == 1) {
set_integer_string(high, "hi", SvPV_nolen(svlo), IFLAG_NONNEG);
mpz_init_set_ui(low, 2);
} else {
set_integer_string(low, "lo", SvPV_nolen(svlo), IFLAG_NONNEG);
set_integer_string(high, "hi", SvPV_nolen(svhi), IFLAG_NONNEG);
}
mpz_clear(seghigh);
mpz_clear(high);
mpz_clear(low);
XPUSHs(sv_2mortal(newRV_noinc((SV*)av)));
void
sieve_range(IN char* strlow, IN char* strwidth, IN char* strdepth)
PREINIT:
mpz_t low, width, depth, high, seghigh;
UV udepth, uwidth, i, nprimes, *list, offset = 0;
PPCODE:
validate_and_set(low, IFLAG_NONNEG);
validate_and_set(width, IFLAG_NONNEG);
validate_and_set(depth, IFLAG_NONNEG);
if (mpz_sgn(width) == 0) {
mpz_clear(low); mpz_clear(width); mpz_clear(depth);
XSRETURN_EMPTY;
}
if (!mpz_fits_uv_p(depth)) {
mpz_clear(low); mpz_clear(width); mpz_clear(depth);
offset += 4294967295U;
}
mpz_clear(seghigh);
mpz_clear(high);
mpz_clear(low);
void
lucas_sequence(IN char* strn, IN char* strP, IN char* strQ, IN char* strk)
PREINIT:
mpz_t U, V, Qk, n, P, Q, k, t;
PPCODE:
validate_and_set(n, IFLAG_POS);
validate_and_set(P, IFLAG_ANY);
validate_and_set(Q, IFLAG_ANY);
validate_and_set(k, IFLAG_NONNEG);
mpz_init(U); mpz_init(V); mpz_init(Qk); mpz_init(t);
lucasuvmod(U, V, P, Q, k, n, t);
mpz_powm(Qk, Q, k, n);
XPUSH_MPZ(U);
XPUSH_MPZ(V);
XPUSH_MPZ(Qk);
holf_factor = 6
squfof_factor = 7
ecm_factor = 8
qs_factor = 9
PREINIT:
mpz_t n, t;
UV arg1, arg2, uf;
static const UV default_arg1[] =
{0, 64000000,64000000,5000000,5000000,0,256000000,100000000,0, 0 };
/*Trial,Rho, Brent, P-1, P+1, Cheb, HOLF, SQUFOF, ECM,QS */
PPCODE:
validate_and_set(n, IFLAG_NONNEG);
{
int cmpr = mpz_cmp_ui(n,1);
if (cmpr <= 0) {
mpz_clear(n);
if (cmpr < 0) XSRETURN_IV(0);
XSRETURN_EMPTY;
}
}
arg1 = default_arg1[ix];
XPUSH_MPZ(n);
mpz_clear(n);
void
factor(IN char* strn)
PREINIT:
mpz_t n;
mpz_t* factors;
int* exponents;
int nfactors, i, j, isneg;
PPCODE:
isneg = validate_and_set(n, IFLAG_ABS);
if (GIMME_V != G_VOID) {
nfactors = factor(n, &factors, &exponents);
if (GIMME_V == G_SCALAR) {
for (i = 0, j = 0; i < nfactors; i++)
j += exponents[i];
PUSHs(sv_2mortal(newSVuv(j)));
} else {
if (isneg)
XPUSH_INT(-1);
}
clear_factors(nfactors, &factors, &exponents);
}
mpz_clear(n);
void divisors(IN char* strn, IN char* strk = 0)
PREINIT:
mpz_t n, k;
mpz_t* divs;
int ndivisors, i;
PPCODE:
validate_and_set(n, IFLAG_NONNEG);
if (strk == 0) {
mpz_init_set(k, n);
} else {
validate_and_set(k, IFLAG_NONNEG);
}
if (GIMME_V == G_VOID) {
/* Nothing */
} else if (GIMME_V == G_SCALAR && mpz_cmp(k, n) >= 0) {
sigma(n, n, 0);
mpz_clear(divs[i]);
Safefree(divs);
}
mpz_clear(k);
mpz_clear(n);
void
sigma(IN char* strn, IN UV k = 1)
PREINIT:
mpz_t n;
PPCODE:
validate_and_set(n, IFLAG_NONNEG);
sigma(n, n, k);
XPUSH_MPZ(n);
mpz_clear(n);
void
todigits(IN char* strn, unsigned int base=10, int length=-1)
PREINIT:
mpz_t n;
uint32_t d, *digits;
PPCODE:
if (base < 2 || base > 0xFFFFFFFFU) croak("invalid base: %u\n", base);
validate_integer_string("n", strn, IFLAG_ANY);
if (strn[0] == '-' || strn[0] == '+') strn++;
if (base == 10) {
uint32_t l = strlen(strn);
New(0, digits, l, uint32_t);
for (d = 0; d < l; d++)
digits[d] = strn[d]-'0';
} else {
mpz_init_set_str(n, strn, 10);
Safefree(digits);
void
fromdigits(IN SV* svp, IN SV* svbase = 0)
PREINIT:
AV *av;
const char *ds;
int i, plen;
size_t j, len;
mpz_t n, base, *digits;
PPCODE:
if (!SvOK(svp)) croak("Parameter must be defined");
if (items > 1 && SvOK(svbase)) {
set_integer_string(base, "base", SvPV_nolen(svbase), IFLAG_NONNEG);
} else {
mpz_init_set_ui(base, 10);
}
if (mpz_cmp_ui(base, 2) < 0) {
SV *basesv = sv_2mortal(sv_return_for_mpz(aTHX_ base));
mpz_clear(base);
croak("fromdigits: invalid base: %s", SvPV_nolen(basesv));
( run in 0.628 second using v1.01-cache-2.11-cpan-4e7a2411597 )