summaryrefslogtreecommitdiff
path: root/dist
diff options
context:
space:
mode:
authorPeter John Acklam <pjacklam@online.no>2011-02-18 07:39:40 -0800
committerFather Chrysostomos <sprout@cpan.org>2011-02-18 07:39:40 -0800
commitde1ac46b8df09e847eed38152e03f6742b4af9de (patch)
treece5ebfab9da328b03f108b114e0c7128b50fb138 /dist
parentbd0e971a15332cc9726bb012b97be7b0f6cadd6f (diff)
downloadperl-de1ac46b8df09e847eed38152e03f6742b4af9de.tar.gz
Update Math::BigInt to CPAN version 1.992
dist/Math-BigInt/lib/Math/BigFloat.pm: - Increment version number. dist/Math-BigInt/lib/Math/BigInt.pm: - Increment version number. - Make from_hex(), from_oct(), and behave more like hex() and oct() in the Perl core, and make from_bin() consistent with from_hex() and from_oct(). This is related to RT #58954. dist/Math-BigInt/lib/Math/BigInt/Calc.pm: - Increment version number. - Make _rem() modify first input arg always, not just sometimes. - Make _modinv() more consistent with the _modinv() method in other libraries (Math::BigInt::GMP, etc.) - In _nok(), use symmetry property nok(n,k) = nok(n,n-k). This cuts computation time tremendously when n and k are large. - In _gcd(), quickly handle zero cases, avoid code duplication, and always modify the first input argument in-place. - Clean up code and add more code comments. - Fix typos. dist/Math-BigInt/lib/Math/BigInt/CalcEmu.pm: - Increment version number. dist/Math-BigInt/t/bigintpm.inc: - Modify tests to something that still fails. dist/Math-BigInt/t/upgrade.inc: - Modify tests to something that still fails.
Diffstat (limited to 'dist')
-rw-r--r--dist/Math-BigInt/lib/Math/BigFloat.pm2
-rw-r--r--dist/Math-BigInt/lib/Math/BigInt.pm194
-rw-r--r--dist/Math-BigInt/lib/Math/BigInt/Calc.pm202
-rw-r--r--dist/Math-BigInt/lib/Math/BigInt/CalcEmu.pm2
-rw-r--r--dist/Math-BigInt/t/bigintpm.inc4
-rw-r--r--dist/Math-BigInt/t/upgrade.inc4
6 files changed, 264 insertions, 144 deletions
diff --git a/dist/Math-BigInt/lib/Math/BigFloat.pm b/dist/Math-BigInt/lib/Math/BigFloat.pm
index 20045a6459..a39d7866b7 100644
--- a/dist/Math-BigInt/lib/Math/BigFloat.pm
+++ b/dist/Math-BigInt/lib/Math/BigFloat.pm
@@ -12,7 +12,7 @@ package Math::BigFloat;
# _a : accuracy
# _p : precision
-$VERSION = '1.991';
+$VERSION = '1.992';
require 5.006002;
require Exporter;
diff --git a/dist/Math-BigInt/lib/Math/BigInt.pm b/dist/Math-BigInt/lib/Math/BigInt.pm
index 9ce39f45e4..a9de794d7e 100644
--- a/dist/Math-BigInt/lib/Math/BigInt.pm
+++ b/dist/Math-BigInt/lib/Math/BigInt.pm
@@ -18,7 +18,7 @@ package Math::BigInt;
my $class = "Math::BigInt";
use 5.006002;
-$VERSION = '1.991';
+$VERSION = '1.992';
@ISA = qw(Exporter);
@EXPORT_OK = qw(objectify bgcd blcm);
@@ -2854,93 +2854,145 @@ sub import
# import done
}
-sub from_hex
- {
- # create a bigint from a hexadecimal string
- my ($self, $hs) = @_;
+sub from_hex {
+ # Create a bigint from a hexadecimal string.
- my $rc = __from_hex($hs);
+ my ($self, $str) = @_;
- return $self->bnan() unless defined $rc;
+ if ($str =~ s/
+ ^
+ ( [+-]? )
+ (0?x)?
+ (
+ [0-9a-fA-F]*
+ ( _ [0-9a-fA-F]+ )*
+ )
+ $
+ //x)
+ {
+ # Get a "clean" version of the string, i.e., non-emtpy and with no
+ # underscores or invalid characters.
- $rc;
- }
+ my $sign = $1;
+ my $chrs = $3;
+ $chrs =~ tr/_//d;
+ $chrs = '0' unless CORE::length $chrs;
-sub from_bin
- {
- # create a bigint from a hexadecimal string
- my ($self, $bs) = @_;
+ # Initialize output.
- my $rc = __from_bin($bs);
+ my $x = Math::BigInt->bzero();
- return $self->bnan() unless defined $rc;
+ # The library method requires a prefix.
- $rc;
- }
+ $x->{value} = $CALC->_from_hex('0x' . $chrs);
-sub from_oct
- {
- # create a bigint from a hexadecimal string
- my ($self, $os) = @_;
+ # Place the sign.
- my $x = $self->bzero();
-
- # strip underscores
- $os =~ s/([0-7])_([0-7])/$1$2/g;
- $os =~ s/([0-7])_([0-7])/$1$2/g;
-
- return $x->bnan() if $os !~ /^[\-\+]?0[0-7]+\z/;
+ if ($sign eq '-' && ! $CALC->_is_zero($x->{value})) {
+ $x->{sign} = '-';
+ }
- my $sign = '+'; $sign = '-' if $os =~ /^-/;
+ return $x;
+ }
- $os =~ s/^[+-]//; # strip sign
- $x->{value} = $CALC->_from_oct($os);
- $x->{sign} = $sign unless $CALC->_is_zero($x->{value}); # no '-0'
- $x;
- }
+ # CORE::hex() parses as much as it can, and ignores any trailing garbage.
+ # For backwards compatibility, we return NaN.
-sub __from_hex
- {
- # internal
- # convert a (ref to) big hex string to BigInt, return undef for error
- my $hs = shift;
+ return $self->bnan();
+}
- my $x = Math::BigInt->bzero();
-
- # strip underscores
- $hs =~ s/([0-9a-fA-F])_([0-9a-fA-F])/$1$2/g;
- $hs =~ s/([0-9a-fA-F])_([0-9a-fA-F])/$1$2/g;
-
- return $x->bnan() if $hs !~ /^[\-\+]?0x[0-9A-Fa-f]+$/;
+sub from_oct {
+ # Create a bigint from an octal string.
- my $sign = '+'; $sign = '-' if $hs =~ /^-/;
+ my ($self, $str) = @_;
- $hs =~ s/^[+-]//; # strip sign
- $x->{value} = $CALC->_from_hex($hs);
- $x->{sign} = $sign unless $CALC->_is_zero($x->{value}); # no '-0'
- $x;
- }
+ if ($str =~ s/
+ ^
+ ( [+-]? )
+ (
+ [0-7]*
+ ( _ [0-7]+ )*
+ )
+ $
+ //x)
+ {
+ # Get a "clean" version of the string, i.e., non-emtpy and with no
+ # underscores or invalid characters.
-sub __from_bin
- {
- # internal
- # convert a (ref to) big binary string to BigInt, return undef for error
- my $bs = shift;
+ my $sign = $1;
+ my $chrs = $2;
+ $chrs =~ tr/_//d;
+ $chrs = '0' unless CORE::length $chrs;
- my $x = Math::BigInt->bzero();
+ # Initialize output.
- # strip underscores
- $bs =~ s/([01])_([01])/$1$2/g;
- $bs =~ s/([01])_([01])/$1$2/g;
- return $x->bnan() if $bs !~ /^[+-]?0b[01]+$/;
+ my $x = Math::BigInt->bzero();
- my $sign = '+'; $sign = '-' if $bs =~ /^\-/;
- $bs =~ s/^[+-]//; # strip sign
+ # The library method requires a prefix.
- $x->{value} = $CALC->_from_bin($bs);
- $x->{sign} = $sign unless $CALC->_is_zero($x->{value}); # no '-0'
- $x;
- }
+ $x->{value} = $CALC->_from_oct('0' . $chrs);
+
+ # Place the sign.
+
+ if ($sign eq '-' && ! $CALC->_is_zero($x->{value})) {
+ $x->{sign} = '-';
+ }
+
+ return $x;
+ }
+
+ # CORE::oct() parses as much as it can, and ignores any trailing garbage.
+ # For backwards compatibility, we return NaN.
+
+ return $self->bnan();
+}
+
+sub from_bin {
+ # Create a bigint from a binary string.
+
+ my ($self, $str) = @_;
+
+ if ($str =~ s/
+ ^
+ ( [+-]? )
+ (0?b)?
+ (
+ [01]*
+ ( _ [01]+ )*
+ )
+ $
+ //x)
+ {
+ # Get a "clean" version of the string, i.e., non-emtpy and with no
+ # underscores or invalid characters.
+
+ my $sign = $1;
+ my $chrs = $3;
+ $chrs =~ tr/_//d;
+ $chrs = '0' unless CORE::length $chrs;
+
+ # Initialize output.
+
+ my $x = Math::BigInt->bzero();
+
+ # The library method requires a prefix.
+
+ $x->{value} = $CALC->_from_bin('0b' . $chrs);
+
+ # Place the sign.
+
+ if ($sign eq '-' && ! $CALC->_is_zero($x->{value})) {
+ $x->{sign} = '-';
+ }
+
+ return $x;
+ }
+
+ # For consistency with from_hex() and from_oct(), we return NaN when the
+ # input is invalid.
+
+ return $self->bnan();
+}
sub _split
{
@@ -2966,9 +3018,9 @@ sub _split
# invalid starting char?
return if $x !~ /^[+-]?(\.?[0-9]|0b[0-1]|0x[0-9a-fA-F])/;
- return __from_hex($x) if $x =~ /^[\-\+]?0x/; # hex string
- return __from_bin($x) if $x =~ /^[\-\+]?0b/; # binary string
-
+ return Math::BigInt->from_hex($x) if $x =~ /^[+-]?0x/; # hex string
+ return Math::BigInt->from_bin($x) if $x =~ /^[+-]?0b/; # binary string
+
# strip underscores between digits
$x =~ s/([0-9])_([0-9])/$1$2/g;
$x =~ s/([0-9])_([0-9])/$1$2/g; # do twice for 1_2_3
diff --git a/dist/Math-BigInt/lib/Math/BigInt/Calc.pm b/dist/Math-BigInt/lib/Math/BigInt/Calc.pm
index e4c3e060d6..a84786ed29 100644
--- a/dist/Math-BigInt/lib/Math/BigInt/Calc.pm
+++ b/dist/Math-BigInt/lib/Math/BigInt/Calc.pm
@@ -4,7 +4,7 @@ use 5.006002;
use strict;
# use warnings; # dont use warnings for older Perls
-our $VERSION = '1.991';
+our $VERSION = '1.992';
# Package to store unsigned big integers in decimal and do math with them
@@ -1355,22 +1355,24 @@ sub _mod
# if possible, use mod shortcut
my ($c,$x,$yo) = @_;
- # slow way since $y to big
+ # slow way since $y too big
if (scalar @$yo > 1)
{
my ($xo,$rem) = _div($c,$x,$yo);
- return $rem;
+ @$x = @$rem;
+ return $x;
}
my $y = $yo->[0];
- # both are single element arrays
+
+ # if both are single element arrays
if (scalar @$x == 1)
{
$x->[0] %= $y;
return $x;
}
- # @y is a single element, but @x has more than one element
+ # if @$x has more than one element, but @$y is a single element
my $b = $BASE % $y;
if ($b == 0)
{
@@ -1381,7 +1383,8 @@ sub _mod
}
elsif ($b == 1)
{
- # else need to go through all elements: O(N), but loop is a bit simplified
+ # else need to go through all elements in @$x: O(N), but loop is a bit
+ # simplified
my $r = 0;
foreach (@$x)
{
@@ -1393,8 +1396,9 @@ sub _mod
}
else
{
- # else need to go through all elements: O(N)
- my $r = 0; my $bm = 1;
+ # else need to go through all elements in @$x: O(N)
+ my $r = 0;
+ my $bm = 1;
foreach (@$x)
{
$r = ($_ * $bm + $r) % $y;
@@ -1408,8 +1412,8 @@ sub _mod
$r = 0 if $r == $y;
$x->[0] = $r;
}
- splice (@$x,1); # keep one element of $x
- $x;
+ @$x = $x->[0]; # keep one element of @$x
+ return $x;
}
##############################################################################
@@ -1533,38 +1537,68 @@ sub _pow
$cx;
}
-sub _nok
- {
- # n over k
- # ref to array, return ref to array
- my ($c,$n,$k) = @_;
+sub _nok {
+ # Return binomial coefficient (n over k).
+ # Given refs to arrays, return ref to array.
+ # First input argument is modified.
- # ( 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
+ 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.
- if (!_is_zero($c,$k))
{
- my $x = _copy($c,$n);
- _sub($c,$n,$k);
- _inc($c,$n);
- my $f = _copy($c,$n); _inc($c,$f); # n = 5, f = 6, d = 2
- my $d = _two($c);
- while (_acmp($c,$f,$x) <= 0) # f <= n ?
- {
- # n = (n * f / d) == 5 * 6 / 2
- $n = _mul($c,$n,$f); $n = _div($c,$n,$d);
- # f = 7, d = 3
- _inc($c,$f); _inc($c,$d);
- }
+ my $twok = _mul($c, _two($c), _copy($c, $k)); # 2 * k
+ if (_acmp($c, $twok, $n) > 0) { # if 2*k > n
+ $k = _sub($c, _copy($c, $n), $k); # k = n - k
+ }
}
- else
- {
- # keep ref to $n and set it to 1
- splice (@$n,1); $n->[0] = 1;
+
+ # 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 (_is_zero($c, $k)) {
+ @$n = 1;
}
- $n;
- }
+
+ else {
+
+ # Make a copy of the original n, since we'll be modifing n in-place.
+
+ my $n_orig = _copy($c, $n);
+
+ # n = 5, f = 6, d = 2 (cf. example above)
+
+ _sub($c, $n, $k);
+ _inc($c, $n);
+
+ my $f = _copy($c, $n);
+ _inc($c, $f);
+
+ my $d = _two($c);
+
+ # while f <= n (the original n, that is) ...
+
+ while (_acmp($c, $f, $n_orig) <= 0) {
+
+ # n = (n * f / d) == 5 * 6 / 2 (cf. example above)
+
+ _mul($c, $n, $f);
+ _div($c, $n, $d);
+
+ # f = 7, d = 3 (cf. example above)
+
+ _inc($c, $f);
+ _inc($c, $d);
+ }
+
+ }
+
+ return $n;
+}
my @factorials = (
1,
@@ -2349,32 +2383,45 @@ sub _from_bin
sub _modinv
{
- # modular inverse
+ # modular multiplicative inverse
my ($c,$x,$y) = @_;
- my $u = _zero($c); my $u1 = _one($c);
- my $a = _copy($c,$y); my $b = _copy($c,$x);
+ # modulo zero
+ if (_is_zero($c, $y)) {
+ return (undef, undef);
+ }
+
+ # modulo one
+ if (_is_one($c, $y)) {
+ return (_zero($c), '+');
+ }
+
+ my $u = _zero($c);
+ my $v = _one($c);
+ my $a = _copy($c,$y);
+ my $b = _copy($c,$x);
- # Euclid's Algorithm for bgcd(), only that we calc bgcd() ($a) and the
- # result ($u) at the same time. See comments in BigInt for why this works.
+ # Euclid's Algorithm for bgcd(), only that we calc bgcd() ($a) and the result
+ # ($u) at the same time. See comments in BigInt for why this works.
my $q;
- ($a, $q, $b) = ($b, _div($c,$a,$b)); # step 1
my $sign = 1;
- while (!_is_zero($c,$b))
- {
- my $t = _add($c, # step 2:
- _mul($c,_copy($c,$u1), $q) , # t = u1 * q
- $u ); # + u
- $u = $u1; # u = u1, u1 = t
- $u1 = $t;
- $sign = -$sign;
- ($a, $q, $b) = ($b, _div($c,$a,$b)); # step 1
- }
+ {
+ ($a, $q, $b) = ($b, _div($c, $a, $b)); # step 1
+ last if _is_zero($c, $b);
+
+ my $t = _add($c, # step 2:
+ _mul($c, _copy($c, $v), $q) , # t = v * q
+ $u ); # + u
+ $u = $v; # u = v
+ $v = $t; # v = t
+ $sign = -$sign;
+ redo;
+ }
# if the gcd is not 1, then return NaN
- return (undef,undef) unless _is_one($c,$a);
-
- ($u1, $sign == 1 ? '+' : '-');
+ return (undef, undef) unless _is_one($c, $a);
+
+ ($v, $sign == 1 ? '+' : '-');
}
sub _modpow
@@ -2420,19 +2467,40 @@ sub _modpow
$num;
}
-sub _gcd
- {
- # greatest common divisor
- my ($c,$x,$y) = @_;
+sub _gcd {
+ # Greatest common divisor.
- while ( (scalar @$y != 1) || ($y->[0] != 0) ) # while ($y != 0)
- {
- my $t = _copy($c,$y);
- $y = _mod($c, $x, $y);
- $x = $t;
+ my ($c, $x, $y) = @_;
+
+ # gcd(0,0) = 0
+ # gcd(0,a) = a, if a != 0
+
+ if (@$x == 1 && $x->[0] == 0) {
+ if (@$y == 1 && $y->[0] == 0) {
+ @$x = 0;
+ } else {
+ @$x = @$y;
+ }
+ return $x;
}
- $x;
- }
+
+ # Until $y is zero ...
+
+ until (@$y == 1 && $y->[0] == 0) {
+
+ # Compute remainder.
+
+ _mod($c, $x, $y);
+
+ # Swap $x and $y.
+
+ my $tmp = [ @$x ];
+ @$x = @$y;
+ $y = $tmp; # no deref here; that would modify input $y
+ }
+
+ return $x;
+}
##############################################################################
##############################################################################
diff --git a/dist/Math-BigInt/lib/Math/BigInt/CalcEmu.pm b/dist/Math-BigInt/lib/Math/BigInt/CalcEmu.pm
index 810665d55f..3f2aa3bdbe 100644
--- a/dist/Math-BigInt/lib/Math/BigInt/CalcEmu.pm
+++ b/dist/Math-BigInt/lib/Math/BigInt/CalcEmu.pm
@@ -5,7 +5,7 @@ use strict;
# use warnings; # dont use warnings for older Perls
use vars qw/$VERSION/;
-$VERSION = '1.991';
+$VERSION = '1.992';
package Math::BigInt;
diff --git a/dist/Math-BigInt/t/bigintpm.inc b/dist/Math-BigInt/t/bigintpm.inc
index da127c3ae1..f5f0fd2812 100644
--- a/dist/Math-BigInt/t/bigintpm.inc
+++ b/dist/Math-BigInt/t/bigintpm.inc
@@ -895,7 +895,7 @@ NaN:-inf:
0b100000000000000000000000000000001:4294967297
0b1000000000000000000000000000000001:8589934593
0b10000000000000000000000000000000001:17179869185
-0b_101:NaN
+0b__101:NaN
0b1_0_1:5
0b0_0_0_1:1
# hex input
@@ -908,7 +908,7 @@ NaN:-inf:
0x12345678:305419896
0x1_2_3_4_56_78:305419896
0xa_b_c_d_e_f:11259375
-0x_123:NaN
+0x__123:NaN
0x9:9
0x11:17
0x21:33
diff --git a/dist/Math-BigInt/t/upgrade.inc b/dist/Math-BigInt/t/upgrade.inc
index 088c567762..c7ecc26434 100644
--- a/dist/Math-BigInt/t/upgrade.inc
+++ b/dist/Math-BigInt/t/upgrade.inc
@@ -395,7 +395,7 @@ NaN:-inf:
0b100000000000000000000000000000001:4294967297
0b1000000000000000000000000000000001:8589934593
0b10000000000000000000000000000000001:17179869185
-0b_101:NaN
+0b__101:NaN
0b1_0_1:5
0b0_0_0_1:1
# hex input
@@ -408,7 +408,7 @@ NaN:-inf:
0x12345678:305419896
0x1_2_3_4_56_78:305419896
0xa_b_c_d_e_f:11259375
-0x_123:NaN
+0x__123:NaN
0x9:9
0x11:17
0x21:33