mirror of
https://github.com/Perl/perl5.git
synced 2026-01-26 08:38:23 +00:00
cpan/Math-BigInt - Update to version 2.003004
2.003004 2025-01-23 * Fix CPAN RT #150252 regarding bdiv() not modifying the invocand object when upgrading/downgrading is enabled. * Add hyperoperator method bhyperop(). This method implements succession, addition, multiplication, exponentiation, tetration, pentation ...).
This commit is contained in:
parent
53119a6d7b
commit
2b29c5b042
@ -766,8 +766,8 @@ our %Modules = (
|
||||
},
|
||||
|
||||
'Math::BigInt' => {
|
||||
'DISTRIBUTION' => 'PJACKLAM/Math-BigInt-2.003003.tar.gz',
|
||||
'SYNCINFO' => 'jkeenan on Wed Jun 12 08:50:03 2024',
|
||||
'DISTRIBUTION' => 'PJACKLAM/Math-BigInt-2.003004.tar.gz',
|
||||
'SYNCINFO' => 'jkeenan on Thu Jan 23 12:59:32 2025',
|
||||
'FILES' => q[cpan/Math-BigInt],
|
||||
'EXCLUDED' => [
|
||||
qr{^xt/},
|
||||
|
||||
@ -21,7 +21,7 @@ use Carp qw< carp croak >;
|
||||
use Scalar::Util qw< blessed >;
|
||||
use Math::BigInt qw< >;
|
||||
|
||||
our $VERSION = '2.003003';
|
||||
our $VERSION = '2.003004';
|
||||
$VERSION =~ tr/_//d;
|
||||
|
||||
require Exporter;
|
||||
|
||||
@ -24,7 +24,7 @@ use warnings;
|
||||
use Carp qw< carp croak >;
|
||||
use Scalar::Util qw< blessed refaddr >;
|
||||
|
||||
our $VERSION = '2.003003';
|
||||
our $VERSION = '2.003004';
|
||||
$VERSION =~ tr/_//d;
|
||||
|
||||
require Exporter;
|
||||
@ -2339,10 +2339,33 @@ sub bdiv {
|
||||
# At this point, both the numerator and denominator are finite numbers, and
|
||||
# the denominator (divisor) is non-zero.
|
||||
|
||||
# Division might return a non-integer result, so upgrade unconditionally, if
|
||||
# upgrading is enabled.
|
||||
# Division in scalar context might return a non-integer result, so upgrade
|
||||
# if upgrading is enabled. In list context, we return the quotient and the
|
||||
# remainder, which are both integers, so upgrading is not necessary.
|
||||
|
||||
return $upgrade -> bdiv($x, $y, @r) if defined $upgrade;
|
||||
if ($upgrade && !$wantarray) {
|
||||
my ($quo, $rem);
|
||||
|
||||
if ($wantarray) {
|
||||
($quo, $rem) = $upgrade -> bdiv($x, $y, @r);
|
||||
} else {
|
||||
$quo = $upgrade -> bdiv($x, $y, @r);
|
||||
}
|
||||
|
||||
if ($quo -> is_int()) {
|
||||
$quo = $quo -> as_int();
|
||||
%$x = %$quo;
|
||||
} else {
|
||||
%$x = %$quo;
|
||||
bless $x, $upgrade;
|
||||
}
|
||||
|
||||
if ($wantarray && $rem -> is_int()) {
|
||||
$rem = $rem -> as_int();
|
||||
}
|
||||
|
||||
return $wantarray ? ($x, $rem) : $x;
|
||||
}
|
||||
|
||||
$r[3] = $y; # no push!
|
||||
|
||||
@ -3214,69 +3237,13 @@ sub bnok {
|
||||
}
|
||||
|
||||
sub buparrow {
|
||||
my $a = shift;
|
||||
my $y = $a -> uparrow(@_);
|
||||
$a -> {value} = $y -> {value};
|
||||
return $a;
|
||||
my ($class, $a, $n, $b, @r) = objectify(3, @_);
|
||||
$a -> bhyperop($n + 2, $b, @r);
|
||||
}
|
||||
|
||||
sub uparrow {
|
||||
# Knuth's up-arrow notation buparrow(a, n, b)
|
||||
#
|
||||
# The following is a simple, recursive implementation of the up-arrow
|
||||
# notation, just to show the idea. Such implementations cause "Deep
|
||||
# recursion on subroutine ..." warnings, so we use a faster, non-recursive
|
||||
# algorithm below with @_ as a stack.
|
||||
#
|
||||
# sub buparrow {
|
||||
# my ($a, $n, $b) = @_;
|
||||
# return $a ** $b if $n == 1;
|
||||
# return $a * $b if $n == 0;
|
||||
# return 1 if $b == 0;
|
||||
# return buparrow($a, $n - 1, buparrow($a, $n, $b - 1));
|
||||
# }
|
||||
|
||||
my ($a, $b, $n) = @_;
|
||||
my $class = ref $a;
|
||||
croak("a must be non-negative") if $a < 0;
|
||||
croak("n must be non-negative") if $n < 0;
|
||||
croak("b must be non-negative") if $b < 0;
|
||||
|
||||
while (@_ >= 3) {
|
||||
|
||||
# return $a ** $b if $n == 1;
|
||||
|
||||
if ($_[-2] == 1) {
|
||||
my ($a, $n, $b) = splice @_, -3;
|
||||
push @_, $a ** $b;
|
||||
next;
|
||||
}
|
||||
|
||||
# return $a * $b if $n == 0;
|
||||
|
||||
if ($_[-2] == 0) {
|
||||
my ($a, $n, $b) = splice @_, -3;
|
||||
push @_, $a * $b;
|
||||
next;
|
||||
}
|
||||
|
||||
# return 1 if $b == 0;
|
||||
|
||||
if ($_[-1] == 0) {
|
||||
splice @_, -3;
|
||||
push @_, $class -> bone();
|
||||
next;
|
||||
}
|
||||
|
||||
# return buparrow($a, $n - 1, buparrow($a, $n, $b - 1));
|
||||
|
||||
my ($a, $n, $b) = splice @_, -3;
|
||||
push @_, ($a, $n - 1,
|
||||
$a, $n, $b - 1);
|
||||
|
||||
}
|
||||
|
||||
pop @_;
|
||||
my ($class, $a, $n, $b, @r) = objectify(3, @_);
|
||||
$a -> hyperop($n + 2, $b, @r);
|
||||
}
|
||||
|
||||
sub backermann {
|
||||
@ -3333,6 +3300,140 @@ sub ackermann {
|
||||
$n;
|
||||
}
|
||||
|
||||
sub bhyperop {
|
||||
my ($class, $a, $n, $b, @r) = objectify(3, @_);
|
||||
|
||||
my $tmp = $a -> hyperop($n, $b);
|
||||
$a -> {value} = $tmp -> {value};
|
||||
return $a -> round(@r);
|
||||
}
|
||||
|
||||
sub hyperop {
|
||||
my ($class, $a, $n, $b, @r) = objectify(3, @_);
|
||||
|
||||
croak("a must be non-negative") if $a < 0;
|
||||
croak("n must be non-negative") if $n < 0;
|
||||
croak("b must be non-negative") if $b < 0;
|
||||
|
||||
# The following is a non-recursive implementation of the hyperoperator,
|
||||
# with special cases handled for speed.
|
||||
|
||||
my @stack = ($a, $n, $b);
|
||||
while (@stack > 1) {
|
||||
my ($a, $n, $b) = splice @stack, -3;
|
||||
|
||||
# Special cases for $b
|
||||
|
||||
if ($b == 2 && $a == 2) {
|
||||
push @stack, $n == 0 ? Math::BigInt -> new("3")
|
||||
: Math::BigInt -> new("4");
|
||||
next;
|
||||
}
|
||||
|
||||
if ($b == 1) {
|
||||
if ($n == 0) {
|
||||
push @stack, Math::BigInt -> new("2");
|
||||
next;
|
||||
}
|
||||
if ($n == 1) {
|
||||
push @stack, $a + 1;
|
||||
next;
|
||||
}
|
||||
push @stack, $a;
|
||||
next;
|
||||
}
|
||||
|
||||
if ($b == 0) {
|
||||
if ($n == 1) {
|
||||
push @stack, $a;
|
||||
next;
|
||||
}
|
||||
if ($n == 2) {
|
||||
push @stack, Math::BigInt -> bzero();
|
||||
next;
|
||||
}
|
||||
push @stack, Math::BigInt -> bone();
|
||||
next;
|
||||
}
|
||||
|
||||
# Special cases for $a
|
||||
|
||||
if ($a == 0) {
|
||||
if ($n == 0) {
|
||||
push @stack, $b + 1;
|
||||
next;
|
||||
}
|
||||
if ($n == 1) {
|
||||
push @stack, $b;
|
||||
next;
|
||||
}
|
||||
if ($n == 2) {
|
||||
push @stack, Math::BigInt -> bzero();
|
||||
next;
|
||||
}
|
||||
if ($n == 3) {
|
||||
push @stack, $b == 0 ? Math::BigInt -> bone()
|
||||
: Math::BigInt -> bzero();
|
||||
next;
|
||||
}
|
||||
push @stack, $b -> is_odd() ? Math::BigInt -> bzero()
|
||||
: Math::BigInt -> bone();
|
||||
next;
|
||||
}
|
||||
|
||||
if ($a == 1) {
|
||||
if ($n == 0 || $n == 1) {
|
||||
push @stack, $b + 1;
|
||||
next;
|
||||
}
|
||||
if ($n == 2) {
|
||||
push @stack, $b;
|
||||
next;
|
||||
}
|
||||
push @stack, Math::BigInt -> bone();
|
||||
next;
|
||||
}
|
||||
|
||||
# Special cases for $n
|
||||
|
||||
if ($n == 4) { # tetration
|
||||
if ($b == 0) {
|
||||
push @stack, Math::BigInt -> bone();
|
||||
next;
|
||||
}
|
||||
my $y = $a;
|
||||
$y = $a ** $y for 2 .. $b;
|
||||
push @stack, $y;
|
||||
next;
|
||||
}
|
||||
|
||||
if ($n == 3) { # exponentiation
|
||||
push @stack, $a ** $b;
|
||||
next;
|
||||
}
|
||||
|
||||
if ($n == 2) { # multiplication
|
||||
push @stack, $a * $b;
|
||||
next;
|
||||
}
|
||||
|
||||
if ($n == 1) { # addition
|
||||
push @stack, $a + $b;
|
||||
next;
|
||||
}
|
||||
|
||||
if ($n == 0) { # succession
|
||||
push @stack, $b + 1;
|
||||
next;
|
||||
}
|
||||
|
||||
push @stack, $a, $n - 1, $a, $n, $b - 1;
|
||||
}
|
||||
|
||||
$a = pop @stack;
|
||||
return $a -> round(@r);
|
||||
}
|
||||
|
||||
sub bsin {
|
||||
my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
|
||||
|
||||
@ -6613,6 +6714,7 @@ Math::BigInt - arbitrary size integer math package
|
||||
$x->bclog10(); # log19($x) rounded up to nearest int
|
||||
$x->bnok($y); # x over y (binomial coefficient n over k)
|
||||
$x->buparrow($n, $y); # Knuth's up-arrow notation
|
||||
$x->bhyperop($n, $y); # n'th hyperoprator
|
||||
$x->backermann($y); # the Ackermann function
|
||||
$x->bsin(); # sine
|
||||
$x->bcos(); # cosine
|
||||
@ -7634,7 +7736,43 @@ integer representing the number of up-arrows. $n = 0 gives multiplication, $n =
|
||||
1 gives exponentiation, $n = 2 gives tetration, $n = 3 gives hexation etc. The
|
||||
following illustrates the relation between the first values of $n.
|
||||
|
||||
See L<https://en.wikipedia.org/wiki/Knuth%27s_up-arrow_notation>.
|
||||
The buparrow() method is equivalent to the L<bhyperop()> method with an offset
|
||||
of two. The following two give the same result:
|
||||
|
||||
$x -> buparrow($n, $b);
|
||||
$x -> bhyperop($n + 2, $b);
|
||||
|
||||
See also L</bhyperop()>,
|
||||
L<https://en.wikipedia.org/wiki/Knuth%27s_up-arrow_notation>.
|
||||
|
||||
=item bhyperop()
|
||||
|
||||
=item hyperop()
|
||||
|
||||
$a -> bhyperop($n, $b); # modifies $a
|
||||
$x = $a -> hyperop($n, $b); # does not modify $a
|
||||
|
||||
H_n(a, b) = a[n]b is the I<n>th hyperoperator,
|
||||
|
||||
n = 0 : succession (b + 1)
|
||||
n = 1 : addition (a + b)
|
||||
n = 2 : multiplication (a * b)
|
||||
n = 3 : exponentiation (a ** b)
|
||||
n = 4 : tetration (a ** a ** ... ** a) (b occurrences of a)
|
||||
...
|
||||
|
||||
/ b+1 if n = 0
|
||||
| a if n = 1 and b = 0
|
||||
H_n(a, b) = a[n]b = | 0 if n = 2 and b = 0
|
||||
| 1 if n >= 3 and b = 0
|
||||
\ H_(n-1)(a, H_n(a, b-1)) otherwise
|
||||
|
||||
Note that the result can be a very large number, even for small operands. Also
|
||||
note that the backend library C<Math::BigInt::GMP> silently returns the
|
||||
incorrect result when the numbers are larger than it can handle. It is better
|
||||
to use C<Math::BigInt::GMPz> or C<Math::BigInt::Pari>.
|
||||
|
||||
See also L</buparrow()>, L<https://en.wikipedia.org/wiki/Hyperoperation>.
|
||||
|
||||
=item backermann()
|
||||
|
||||
|
||||
@ -7,7 +7,7 @@ use warnings;
|
||||
use Carp qw< carp croak >;
|
||||
use Math::BigInt::Lib;
|
||||
|
||||
our $VERSION = '2.003003';
|
||||
our $VERSION = '2.003004';
|
||||
$VERSION =~ tr/_//d;
|
||||
|
||||
our @ISA = ('Math::BigInt::Lib');
|
||||
@ -2461,16 +2461,17 @@ sub _modpow {
|
||||
return $num;
|
||||
}
|
||||
|
||||
# $num = $c->_mod($num, $mod); # this does not make it faster
|
||||
# We could do the following, but it doesn't actually save any time. The
|
||||
# _copy() is needed in case $num and $mod are the same object.
|
||||
#$num = $c->_mod($c->_copy($num), $mod);
|
||||
|
||||
my $acc = $c->_copy($num);
|
||||
my $t = $c->_one();
|
||||
|
||||
my $expbin = $c->_as_bin($exp);
|
||||
$expbin =~ s/^0b//;
|
||||
my $expbin = $c->_to_bin($exp);
|
||||
my $len = length($expbin);
|
||||
while (--$len >= 0) {
|
||||
if (substr($expbin, $len, 1) eq '1') { # is_odd
|
||||
while ($len--) {
|
||||
if (substr($expbin, $len, 1) eq '1') { # if odd
|
||||
$t = $c->_mul($t, $acc);
|
||||
$t = $c->_mod($t, $mod);
|
||||
}
|
||||
|
||||
@ -4,7 +4,7 @@ use 5.006001;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
our $VERSION = '2.003003';
|
||||
our $VERSION = '2.003004';
|
||||
$VERSION =~ tr/_//d;
|
||||
|
||||
use Carp;
|
||||
@ -1906,17 +1906,19 @@ sub _modpow {
|
||||
: $class -> _zero();
|
||||
}
|
||||
|
||||
# $num = $class -> _mod($num, $mod); # this does not make it faster
|
||||
# We could do the following, but it doesn't actually save any time. The
|
||||
# _copy() is needed in case $num and $mod are the same object.
|
||||
|
||||
$num = $class -> _mod($class -> _copy($num), $mod);
|
||||
|
||||
my $acc = $class -> _copy($num);
|
||||
my $t = $class -> _one();
|
||||
|
||||
my $expbin = $class -> _as_bin($exp);
|
||||
$expbin =~ s/^0b//;
|
||||
my $expbin = $class -> _to_bin($exp);
|
||||
my $len = length($expbin);
|
||||
|
||||
while (--$len >= 0) {
|
||||
if (substr($expbin, $len, 1) eq '1') {
|
||||
while ($len--) {
|
||||
if (substr($expbin, $len, 1) eq '1') { # if odd
|
||||
$t = $class -> _mul($t, $acc);
|
||||
$t = $class -> _mod($t, $mod);
|
||||
}
|
||||
|
||||
@ -23,7 +23,7 @@ use Scalar::Util qw< blessed >;
|
||||
|
||||
use Math::BigFloat ();
|
||||
|
||||
our $VERSION = '2.003003';
|
||||
our $VERSION = '2.003004';
|
||||
$VERSION =~ tr/_//d;
|
||||
|
||||
our @ISA = qw(Math::BigFloat);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user