Math-AnyNum
view release on metacpan or search on metacpan
lib/Math/AnyNum.pm view on Meta::CPAN
#
## Ratmod
#
sub ratmod ($$) {
my ($n, $m) = @_;
$n = _star2obj($n) // goto &nan;
$m = _star2mpz($m) // goto &nan;
my $r = Math::GMPz::Rmpz_init();
if (ref($n) eq 'Math::GMPz') {
Math::GMPz::Rmpz_mod($r, $n, $m);
}
else {
$r = _modular_rational($n, $m) // goto &nan;
Math::GMPz::Rmpz_mod($r, $r, $m);
}
bless \$r;
}
#
## Powmod
#
sub powmod ($$$) {
my ($n, $k, $m) = @_;
$n = _star2obj($n) // goto &nan;
$k = _star2mpz($k) // goto &nan;
$m = _star2mpz($m) // goto &nan;
Math::GMPz::Rmpz_sgn($m) || goto &nan;
if (ref($n) ne 'Math::GMPz') {
if (__is_int__($n)) {
$n = _any2mpz($n) // goto &nan;
}
else {
$n = _modular_rational($n, $m) // goto &nan;
}
}
my $r = Math::GMPz::Rmpz_init();
if (Math::GMPz::Rmpz_sgn($k) < 0) {
Math::GMPz::Rmpz_invert($r, $n, $m) or goto &nan;
}
Math::GMPz::Rmpz_fits_ulong_p($k)
? Math::GMPz::Rmpz_powm_ui($r, $n, Math::GMPz::Rmpz_get_ui($k), $m)
: Math::GMPz::Rmpz_powm($r, $n, $k, $m);
bless \$r;
}
#
## Geometric summation formula
## https://en.wikipedia.org/wiki/Geometric_series
#
sub geometric_sum ($$) {
my ($n, $r) = @_;
$n = ref($n) eq __PACKAGE__ ? $$n : _star2obj($n);
$r = ref($r) eq __PACKAGE__ ? $$r : _star2obj($r);
bless \__div__(__sub__(__pow__($r, __add__($n, 1)), 1), __sub__($r, 1));
}
#
## Faulhaber's summation formula
## https://en.wikipedia.org/wiki/Faulhaber%27s_formula
#
sub faulhaber_sum ($$) {
my ($n, $p) = @_;
$n = _star2mpz($n) // goto &nan;
$p = _star2ui($p) // goto &nan;
if ($p == 0) {
return bless \$n;
}
if ($p == 1 or $p == 3) {
my $r = Math::GMPz::Rmpz_init();
Math::GMPz::Rmpz_add_ui($r, $n, 1);
Math::GMPz::Rmpz_mul($r, $r, $n);
Math::GMPz::Rmpz_div_2exp($r, $r, 1);
Math::GMPz::Rmpz_mul($r, $r, $r) if ($p == 3);
return bless \$r;
}
state $z = Math::GMPz::Rmpz_init_nobless();
if ($p == 2) { # n*(n+1)*(2*n+1)/6
my $r = Math::GMPz::Rmpz_init();
Math::GMPz::Rmpz_add_ui($z, $n, 1);
Math::GMPz::Rmpz_mul($r, $z, $n);
Math::GMPz::Rmpz_mul_2exp($z, $z, 1);
Math::GMPz::Rmpz_sub_ui($z, $z, 1);
Math::GMPz::Rmpz_mul($r, $r, $z);
Math::GMPz::Rmpz_divexact_ui($r, $r, 6);
return bless \$r;
}
# When p >= n, sum the powers directly.
if (Math::GMPz::Rmpz_cmp_ui($n, $p) <= 0) {
my $r = Math::GMPz::Rmpz_init_set_ui(0);
foreach my $k (1 .. Math::GMPz::Rmpz_get_ui($n)) {
Math::GMPz::Rmpz_ui_pow_ui($z, $k, $p);
Math::GMPz::Rmpz_add($r, $r, $z);
}
return bless \$r;
}
my @B = _bernoulli_numbers($p);
my $q = Math::GMPq::Rmpq_init();
my $u = Math::GMPz::Rmpz_init_set_ui(1);
my $sum = Math::GMPq::Rmpq_init();
Math::GMPq::Rmpq_set_ui($sum, 0, 1);
# Sum_{k=1..n} k^p = 1/(p+1) * Sum_{j=0..p} binomial(p+1, j) * n^(p-j+1) * bernoulli(j)
# = 1/(p+1) * Sum_{j=0..p} binomial(p+1, p-j) * n^(j+1) * bernoulli(p-j)
foreach my $j (0 .. $p - 2) {
Math::GMPz::Rmpz_mul($u, $u, $n);
# Skip when bernoulli(p-j) == 0
( run in 0.854 second using v1.01-cache-2.11-cpan-e1769b4cff6 )