Skip to content

Commit 2b29c5b

Browse files
Peter John Acklamjkeenan
authored andcommitted
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 ...).
1 parent 53119a6 commit 2b29c5b

File tree

6 files changed

+222
-81
lines changed

6 files changed

+222
-81
lines changed

Porting/Maintainers.pl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -766,8 +766,8 @@ package Maintainers;
766766
},
767767

768768
'Math::BigInt' => {
769-
'DISTRIBUTION' => 'PJACKLAM/Math-BigInt-2.003003.tar.gz',
770-
'SYNCINFO' => 'jkeenan on Wed Jun 12 08:50:03 2024',
769+
'DISTRIBUTION' => 'PJACKLAM/Math-BigInt-2.003004.tar.gz',
770+
'SYNCINFO' => 'jkeenan on Thu Jan 23 12:59:32 2025',
771771
'FILES' => q[cpan/Math-BigInt],
772772
'EXCLUDED' => [
773773
qr{^xt/},

cpan/Math-BigInt/lib/Math/BigFloat.pm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use Carp qw< carp croak >;
2121
use Scalar::Util qw< blessed >;
2222
use Math::BigInt qw< >;
2323

24-
our $VERSION = '2.003003';
24+
our $VERSION = '2.003004';
2525
$VERSION =~ tr/_//d;
2626

2727
require Exporter;

cpan/Math-BigInt/lib/Math/BigInt.pm

Lines changed: 203 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ use warnings;
2424
use Carp qw< carp croak >;
2525
use Scalar::Util qw< blessed refaddr >;
2626

27-
our $VERSION = '2.003003';
27+
our $VERSION = '2.003004';
2828
$VERSION =~ tr/_//d;
2929

3030
require Exporter;
@@ -2339,10 +2339,33 @@ sub bdiv {
23392339
# At this point, both the numerator and denominator are finite numbers, and
23402340
# the denominator (divisor) is non-zero.
23412341

2342-
# Division might return a non-integer result, so upgrade unconditionally, if
2343-
# upgrading is enabled.
2342+
# Division in scalar context might return a non-integer result, so upgrade
2343+
# if upgrading is enabled. In list context, we return the quotient and the
2344+
# remainder, which are both integers, so upgrading is not necessary.
2345+
2346+
if ($upgrade && !$wantarray) {
2347+
my ($quo, $rem);
2348+
2349+
if ($wantarray) {
2350+
($quo, $rem) = $upgrade -> bdiv($x, $y, @r);
2351+
} else {
2352+
$quo = $upgrade -> bdiv($x, $y, @r);
2353+
}
23442354

2345-
return $upgrade -> bdiv($x, $y, @r) if defined $upgrade;
2355+
if ($quo -> is_int()) {
2356+
$quo = $quo -> as_int();
2357+
%$x = %$quo;
2358+
} else {
2359+
%$x = %$quo;
2360+
bless $x, $upgrade;
2361+
}
2362+
2363+
if ($wantarray && $rem -> is_int()) {
2364+
$rem = $rem -> as_int();
2365+
}
2366+
2367+
return $wantarray ? ($x, $rem) : $x;
2368+
}
23462369

23472370
$r[3] = $y; # no push!
23482371

@@ -3214,69 +3237,13 @@ sub bnok {
32143237
}
32153238

32163239
sub buparrow {
3217-
my $a = shift;
3218-
my $y = $a -> uparrow(@_);
3219-
$a -> {value} = $y -> {value};
3220-
return $a;
3240+
my ($class, $a, $n, $b, @r) = objectify(3, @_);
3241+
$a -> bhyperop($n + 2, $b, @r);
32213242
}
32223243

32233244
sub uparrow {
3224-
# Knuth's up-arrow notation buparrow(a, n, b)
3225-
#
3226-
# The following is a simple, recursive implementation of the up-arrow
3227-
# notation, just to show the idea. Such implementations cause "Deep
3228-
# recursion on subroutine ..." warnings, so we use a faster, non-recursive
3229-
# algorithm below with @_ as a stack.
3230-
#
3231-
# sub buparrow {
3232-
# my ($a, $n, $b) = @_;
3233-
# return $a ** $b if $n == 1;
3234-
# return $a * $b if $n == 0;
3235-
# return 1 if $b == 0;
3236-
# return buparrow($a, $n - 1, buparrow($a, $n, $b - 1));
3237-
# }
3238-
3239-
my ($a, $b, $n) = @_;
3240-
my $class = ref $a;
3241-
croak("a must be non-negative") if $a < 0;
3242-
croak("n must be non-negative") if $n < 0;
3243-
croak("b must be non-negative") if $b < 0;
3244-
3245-
while (@_ >= 3) {
3246-
3247-
# return $a ** $b if $n == 1;
3248-
3249-
if ($_[-2] == 1) {
3250-
my ($a, $n, $b) = splice @_, -3;
3251-
push @_, $a ** $b;
3252-
next;
3253-
}
3254-
3255-
# return $a * $b if $n == 0;
3256-
3257-
if ($_[-2] == 0) {
3258-
my ($a, $n, $b) = splice @_, -3;
3259-
push @_, $a * $b;
3260-
next;
3261-
}
3262-
3263-
# return 1 if $b == 0;
3264-
3265-
if ($_[-1] == 0) {
3266-
splice @_, -3;
3267-
push @_, $class -> bone();
3268-
next;
3269-
}
3270-
3271-
# return buparrow($a, $n - 1, buparrow($a, $n, $b - 1));
3272-
3273-
my ($a, $n, $b) = splice @_, -3;
3274-
push @_, ($a, $n - 1,
3275-
$a, $n, $b - 1);
3276-
3277-
}
3278-
3279-
pop @_;
3245+
my ($class, $a, $n, $b, @r) = objectify(3, @_);
3246+
$a -> hyperop($n + 2, $b, @r);
32803247
}
32813248

32823249
sub backermann {
@@ -3333,6 +3300,140 @@ sub ackermann {
33333300
$n;
33343301
}
33353302

3303+
sub bhyperop {
3304+
my ($class, $a, $n, $b, @r) = objectify(3, @_);
3305+
3306+
my $tmp = $a -> hyperop($n, $b);
3307+
$a -> {value} = $tmp -> {value};
3308+
return $a -> round(@r);
3309+
}
3310+
3311+
sub hyperop {
3312+
my ($class, $a, $n, $b, @r) = objectify(3, @_);
3313+
3314+
croak("a must be non-negative") if $a < 0;
3315+
croak("n must be non-negative") if $n < 0;
3316+
croak("b must be non-negative") if $b < 0;
3317+
3318+
# The following is a non-recursive implementation of the hyperoperator,
3319+
# with special cases handled for speed.
3320+
3321+
my @stack = ($a, $n, $b);
3322+
while (@stack > 1) {
3323+
my ($a, $n, $b) = splice @stack, -3;
3324+
3325+
# Special cases for $b
3326+
3327+
if ($b == 2 && $a == 2) {
3328+
push @stack, $n == 0 ? Math::BigInt -> new("3")
3329+
: Math::BigInt -> new("4");
3330+
next;
3331+
}
3332+
3333+
if ($b == 1) {
3334+
if ($n == 0) {
3335+
push @stack, Math::BigInt -> new("2");
3336+
next;
3337+
}
3338+
if ($n == 1) {
3339+
push @stack, $a + 1;
3340+
next;
3341+
}
3342+
push @stack, $a;
3343+
next;
3344+
}
3345+
3346+
if ($b == 0) {
3347+
if ($n == 1) {
3348+
push @stack, $a;
3349+
next;
3350+
}
3351+
if ($n == 2) {
3352+
push @stack, Math::BigInt -> bzero();
3353+
next;
3354+
}
3355+
push @stack, Math::BigInt -> bone();
3356+
next;
3357+
}
3358+
3359+
# Special cases for $a
3360+
3361+
if ($a == 0) {
3362+
if ($n == 0) {
3363+
push @stack, $b + 1;
3364+
next;
3365+
}
3366+
if ($n == 1) {
3367+
push @stack, $b;
3368+
next;
3369+
}
3370+
if ($n == 2) {
3371+
push @stack, Math::BigInt -> bzero();
3372+
next;
3373+
}
3374+
if ($n == 3) {
3375+
push @stack, $b == 0 ? Math::BigInt -> bone()
3376+
: Math::BigInt -> bzero();
3377+
next;
3378+
}
3379+
push @stack, $b -> is_odd() ? Math::BigInt -> bzero()
3380+
: Math::BigInt -> bone();
3381+
next;
3382+
}
3383+
3384+
if ($a == 1) {
3385+
if ($n == 0 || $n == 1) {
3386+
push @stack, $b + 1;
3387+
next;
3388+
}
3389+
if ($n == 2) {
3390+
push @stack, $b;
3391+
next;
3392+
}
3393+
push @stack, Math::BigInt -> bone();
3394+
next;
3395+
}
3396+
3397+
# Special cases for $n
3398+
3399+
if ($n == 4) { # tetration
3400+
if ($b == 0) {
3401+
push @stack, Math::BigInt -> bone();
3402+
next;
3403+
}
3404+
my $y = $a;
3405+
$y = $a ** $y for 2 .. $b;
3406+
push @stack, $y;
3407+
next;
3408+
}
3409+
3410+
if ($n == 3) { # exponentiation
3411+
push @stack, $a ** $b;
3412+
next;
3413+
}
3414+
3415+
if ($n == 2) { # multiplication
3416+
push @stack, $a * $b;
3417+
next;
3418+
}
3419+
3420+
if ($n == 1) { # addition
3421+
push @stack, $a + $b;
3422+
next;
3423+
}
3424+
3425+
if ($n == 0) { # succession
3426+
push @stack, $b + 1;
3427+
next;
3428+
}
3429+
3430+
push @stack, $a, $n - 1, $a, $n, $b - 1;
3431+
}
3432+
3433+
$a = pop @stack;
3434+
return $a -> round(@r);
3435+
}
3436+
33363437
sub bsin {
33373438
my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
33383439

@@ -6613,6 +6714,7 @@ Math::BigInt - arbitrary size integer math package
66136714
$x->bclog10(); # log19($x) rounded up to nearest int
66146715
$x->bnok($y); # x over y (binomial coefficient n over k)
66156716
$x->buparrow($n, $y); # Knuth's up-arrow notation
6717+
$x->bhyperop($n, $y); # n'th hyperoprator
66166718
$x->backermann($y); # the Ackermann function
66176719
$x->bsin(); # sine
66186720
$x->bcos(); # cosine
@@ -7634,7 +7736,43 @@ integer representing the number of up-arrows. $n = 0 gives multiplication, $n =
76347736
1 gives exponentiation, $n = 2 gives tetration, $n = 3 gives hexation etc. The
76357737
following illustrates the relation between the first values of $n.
76367738
7637-
See L<https://en.wikipedia.org/wiki/Knuth%27s_up-arrow_notation>.
7739+
The buparrow() method is equivalent to the L<bhyperop()> method with an offset
7740+
of two. The following two give the same result:
7741+
7742+
$x -> buparrow($n, $b);
7743+
$x -> bhyperop($n + 2, $b);
7744+
7745+
See also L</bhyperop()>,
7746+
L<https://en.wikipedia.org/wiki/Knuth%27s_up-arrow_notation>.
7747+
7748+
=item bhyperop()
7749+
7750+
=item hyperop()
7751+
7752+
$a -> bhyperop($n, $b); # modifies $a
7753+
$x = $a -> hyperop($n, $b); # does not modify $a
7754+
7755+
H_n(a, b) = a[n]b is the I<n>th hyperoperator,
7756+
7757+
n = 0 : succession (b + 1)
7758+
n = 1 : addition (a + b)
7759+
n = 2 : multiplication (a * b)
7760+
n = 3 : exponentiation (a ** b)
7761+
n = 4 : tetration (a ** a ** ... ** a) (b occurrences of a)
7762+
...
7763+
7764+
/ b+1 if n = 0
7765+
| a if n = 1 and b = 0
7766+
H_n(a, b) = a[n]b = | 0 if n = 2 and b = 0
7767+
| 1 if n >= 3 and b = 0
7768+
\ H_(n-1)(a, H_n(a, b-1)) otherwise
7769+
7770+
Note that the result can be a very large number, even for small operands. Also
7771+
note that the backend library C<Math::BigInt::GMP> silently returns the
7772+
incorrect result when the numbers are larger than it can handle. It is better
7773+
to use C<Math::BigInt::GMPz> or C<Math::BigInt::Pari>.
7774+
7775+
See also L</buparrow()>, L<https://en.wikipedia.org/wiki/Hyperoperation>.
76387776
76397777
=item backermann()
76407778

cpan/Math-BigInt/lib/Math/BigInt/Calc.pm

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use warnings;
77
use Carp qw< carp croak >;
88
use Math::BigInt::Lib;
99

10-
our $VERSION = '2.003003';
10+
our $VERSION = '2.003004';
1111
$VERSION =~ tr/_//d;
1212

1313
our @ISA = ('Math::BigInt::Lib');
@@ -2461,16 +2461,17 @@ sub _modpow {
24612461
return $num;
24622462
}
24632463

2464-
# $num = $c->_mod($num, $mod); # this does not make it faster
2464+
# We could do the following, but it doesn't actually save any time. The
2465+
# _copy() is needed in case $num and $mod are the same object.
2466+
#$num = $c->_mod($c->_copy($num), $mod);
24652467

24662468
my $acc = $c->_copy($num);
24672469
my $t = $c->_one();
24682470

2469-
my $expbin = $c->_as_bin($exp);
2470-
$expbin =~ s/^0b//;
2471+
my $expbin = $c->_to_bin($exp);
24712472
my $len = length($expbin);
2472-
while (--$len >= 0) {
2473-
if (substr($expbin, $len, 1) eq '1') { # is_odd
2473+
while ($len--) {
2474+
if (substr($expbin, $len, 1) eq '1') { # if odd
24742475
$t = $c->_mul($t, $acc);
24752476
$t = $c->_mod($t, $mod);
24762477
}

cpan/Math-BigInt/lib/Math/BigInt/Lib.pm

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use 5.006001;
44
use strict;
55
use warnings;
66

7-
our $VERSION = '2.003003';
7+
our $VERSION = '2.003004';
88
$VERSION =~ tr/_//d;
99

1010
use Carp;
@@ -1906,17 +1906,19 @@ sub _modpow {
19061906
: $class -> _zero();
19071907
}
19081908

1909-
# $num = $class -> _mod($num, $mod); # this does not make it faster
1909+
# We could do the following, but it doesn't actually save any time. The
1910+
# _copy() is needed in case $num and $mod are the same object.
1911+
1912+
$num = $class -> _mod($class -> _copy($num), $mod);
19101913

19111914
my $acc = $class -> _copy($num);
19121915
my $t = $class -> _one();
19131916

1914-
my $expbin = $class -> _as_bin($exp);
1915-
$expbin =~ s/^0b//;
1917+
my $expbin = $class -> _to_bin($exp);
19161918
my $len = length($expbin);
19171919

1918-
while (--$len >= 0) {
1919-
if (substr($expbin, $len, 1) eq '1') {
1920+
while ($len--) {
1921+
if (substr($expbin, $len, 1) eq '1') { # if odd
19201922
$t = $class -> _mul($t, $acc);
19211923
$t = $class -> _mod($t, $mod);
19221924
}

0 commit comments

Comments
 (0)