Math-BigInt
view release on metacpan or search on metacpan
lib/Math/BigInt/Calc.pm view on Meta::CPAN
}
# If we must shift the elements within the array ...
if ($q) {
unshift @$x, (0) x $q;
}
} else {
$x = $c->_mul($x, $c->_pow($b, $n));
}
return $x;
}
sub _pow {
# power of $x to $y
# ref to array, ref to array, return ref to array
my ($c, $cx, $cy) = @_;
if (@$cy == 1 && $cy->[0] == 0) {
splice(@$cx, 1);
$cx->[0] = 1; # y == 0 => x => 1
return $cx;
}
if ((@$cx == 1 && $cx->[0] == 1) || # x == 1
(@$cy == 1 && $cy->[0] == 1)) # or y == 1
{
return $cx;
}
if (@$cx == 1 && $cx->[0] == 0) {
splice (@$cx, 1);
$cx->[0] = 0; # 0 ** y => 0 (if not y <= 0)
return $cx;
}
my $pow2 = $c->_one();
my $y_bin = $c->_as_bin($cy);
$y_bin =~ s/^0b//;
my $len = length($y_bin);
while (--$len > 0) {
$c->_mul($pow2, $cx) if substr($y_bin, $len, 1) eq '1'; # is odd?
$c->_mul($cx, $cx);
}
$c->_mul($cx, $pow2);
$cx;
}
sub _nok {
# Return binomial coefficient (n over k).
# Given refs to arrays, return ref to array.
# First input argument is modified.
my ($c, $n, $k) = @_;
# If k > n/2, or, equivalently, 2*k > n, compute nok(n, k) as
# nok(n, n-k), to minimize the number if iterations in the loop.
{
my $twok = $c->_mul($c->_two(), $c->_copy($k)); # 2 * k
if ($c->_acmp($twok, $n) > 0) { # if 2*k > n
$k = $c->_sub($c->_copy($n), $k); # k = n - k
}
}
# Example:
#
# / 7 \ 7! 1*2*3*4 * 5*6*7 5 * 6 * 7 6 7
# | | = --------- = --------------- = --------- = 5 * - * -
# \ 3 / (7-3)! 3! 1*2*3*4 * 1*2*3 1 * 2 * 3 2 3
if ($c->_is_zero($k)) {
@$n = 1;
} else {
# Make a copy of the original n, since we'll be modifying n in-place.
my $n_orig = $c->_copy($n);
# n = 5, f = 6, d = 2 (cf. example above)
$c->_sub($n, $k);
$c->_inc($n);
my $f = $c->_copy($n);
$c->_inc($f);
my $d = $c->_two();
# while f <= n (the original n, that is) ...
while ($c->_acmp($f, $n_orig) <= 0) {
# n = (n * f / d) == 5 * 6 / 2 (cf. example above)
$c->_mul($n, $f);
$c->_div($n, $d);
# f = 7, d = 3 (cf. example above)
$c->_inc($f);
$c->_inc($d);
}
}
return $n;
}
sub _fac {
# factorial of $x
# ref to array, return ref to array
my ($c, $cx) = @_;
# We cache the smallest values. Don't assume that a single element has a
# value larger than 9 or else it won't work with a $BASE_LEN of 1.
( run in 1.061 second using v1.01-cache-2.11-cpan-71847e10f99 )