summaryrefslogtreecommitdiff
path: root/cpan/Math-BigInt
diff options
context:
space:
mode:
authorHugo van der Sanden <hv@crypt.org>2022-04-12 19:30:53 +0100
committerRicardo Signes <rjbs@semiotic.systems>2022-04-17 10:18:13 -0400
commit8dec64698880d15d36aa3ca539b11827e014b51e (patch)
tree6ef5812a22ee603818f18aa6af224bf8cf8c4fb7 /cpan/Math-BigInt
parenta5f79404890330b9ec94ceec5a976b34e7720e37 (diff)
downloadperl-8dec64698880d15d36aa3ca539b11827e014b51e.tar.gz
Update Math-BigInt to CPAN version 1.999830
[DELTA] * Improve upgrading and downgrading. This work is not complete. Some methods still don't downgrade when they should.
Diffstat (limited to 'cpan/Math-BigInt')
-rw-r--r--cpan/Math-BigInt/lib/Math/BigFloat.pm365
-rw-r--r--cpan/Math-BigInt/lib/Math/BigInt.pm51
-rw-r--r--cpan/Math-BigInt/lib/Math/BigInt/Calc.pm3
-rw-r--r--cpan/Math-BigInt/lib/Math/BigInt/Lib.pm3
-rw-r--r--cpan/Math-BigInt/t/downgrade.t490
-rw-r--r--cpan/Math-BigInt/t/upgrade.t22
6 files changed, 759 insertions, 175 deletions
diff --git a/cpan/Math-BigInt/lib/Math/BigFloat.pm b/cpan/Math-BigInt/lib/Math/BigFloat.pm
index 8668270cbe..d404f66af3 100644
--- a/cpan/Math-BigInt/lib/Math/BigFloat.pm
+++ b/cpan/Math-BigInt/lib/Math/BigFloat.pm
@@ -20,7 +20,8 @@ use Carp qw< carp croak >;
use Scalar::Util qw< blessed >;
use Math::BigInt qw< >;
-our $VERSION = '1.999829';
+our $VERSION = '1.999830';
+$VERSION =~ tr/_//d;
require Exporter;
our @ISA = qw/Math::BigInt/;
@@ -426,11 +427,10 @@ sub new {
}
}
-
# Handle Infs.
if ($wanted =~ /^\s*([+-]?)inf(inity)?\s*\z/i) {
- return $downgrade->new($wanted) if $downgrade;
+ return $downgrade->new($wanted) if defined $downgrade;
my $sgn = $1 || '+';
$self = $class -> binf($sgn);
$self->round(@r) unless @r >= 2 && !defined($r[0]) && !defined($r[1]);
@@ -440,7 +440,7 @@ sub new {
# Handle explicit NaNs (not the ones returned due to invalid input).
if ($wanted =~ /^\s*([+-]?)nan\s*\z/i) {
- return $downgrade->new($wanted) if $downgrade;
+ return $downgrade->new($wanted) if defined $downgrade;
$self = $class -> bnan();
$self->round(@r) unless @r >= 2 && !defined $r[0] && !defined $r[1];
return $self;
@@ -457,7 +457,7 @@ sub new {
$
/x)
{
- return $downgrade->new($1 . $2) if $downgrade;
+ return $downgrade->new($1 . $2) if defined $downgrade;
$self->{sign} = $1 || '+';
$self->{_m} = $LIB -> _new($2);
$self->{_es} = '+';
@@ -513,7 +513,6 @@ sub new {
# The value is an integer iff the exponent is non-negative.
if ($parts[2] eq '+' && $downgrade) {
- #return $downgrade->new($str, @r);
return $downgrade->new($wanted, @r);
}
@@ -548,9 +547,8 @@ sub from_dec {
# The value is an integer iff the exponent is non-negative.
- if ($parts[2] eq '+' && $downgrade) {
- #$str = $parts[0] . $LIB -> _lsft($parts[1], $parts[3], 10);
- return $downgrade->new($str, @r);
+ if ($parts[2] eq '+') {
+ return $downgrade->new($str, @r) if defined $downgrade;
}
($self->{sign}, $self->{_m}, $self->{_es}, $self->{_e}) = @parts;
@@ -581,8 +579,7 @@ sub from_hex {
# The value is an integer iff the exponent is non-negative.
- if ($parts[2] eq '+' && $downgrade) {
- #$str = $parts[0] . $LIB -> _lsft($parts[1], $parts[3], 10);
+ if ($parts[2] eq '+' && defined $downgrade) {
return $downgrade -> from_hex($str, @r);
}
@@ -614,9 +611,8 @@ sub from_oct {
# The value is an integer iff the exponent is non-negative.
- if ($parts[2] eq '+' && $downgrade) {
- #$str = $parts[0] . $LIB -> _lsft($parts[1], $parts[3], 10);
- return $downgrade -> from_oct($str, @r);
+ if ($parts[2] eq '+') {
+ return $downgrade -> from_oct($str, @r) if defined $downgrade;
}
($self->{sign}, $self->{_m}, $self->{_es}, $self->{_e}) = @parts;
@@ -647,9 +643,8 @@ sub from_bin {
# The value is an integer iff the exponent is non-negative.
- if ($parts[2] eq '+' && $downgrade) {
- #$str = $parts[0] . $LIB -> _lsft($parts[1], $parts[3], 10);
- return $downgrade -> from_bin($str, @r);
+ if ($parts[2] eq '+') {
+ return $downgrade -> from_bin($str, @r) if defined $downgrade;
}
($self->{sign}, $self->{_m}, $self->{_es}, $self->{_e}) = @parts;
@@ -814,6 +809,9 @@ sub from_ieee754 {
} else {
$self = $x;
}
+
+ return $downgrade -> new($x, @r)
+ if defined($downgrade) && $x -> is_int();
return $self -> round(@r);
}
@@ -836,6 +834,8 @@ sub bzero {
$self->import() if $IMPORT == 0; # make require work
return if $selfref && $self->modify('bzero');
+ return $downgrade->bzero() if defined $downgrade;
+
$self = bless {}, $class unless $selfref;
$self -> {sign} = '+';
@@ -878,6 +878,8 @@ sub bone {
$self->import() if $IMPORT == 0; # make require work
return if $selfref && $self->modify('bone');
+ return $downgrade->bone() if defined $downgrade;
+
my $sign = shift;
$sign = defined $sign && $sign =~ /^\s*-/ ? "-" : "+";
@@ -918,6 +920,8 @@ sub binf {
unshift @_, __PACKAGE__;
}
+ return $downgrade->binf(@_) if defined $downgrade;
+
my $self = shift;
my $selfref = ref $self;
my $class = $selfref || $self;
@@ -970,6 +974,8 @@ sub bnan {
unshift @_, __PACKAGE__;
}
+ return $downgrade->bnan(@_) if defined $downgrade;
+
my $self = shift;
my $selfref = ref $self;
my $class = $selfref || $self;
@@ -1050,7 +1056,7 @@ sub bpi {
{
$r[0] = $self;
$class = __PACKAGE__;
- $self = $class -> bzero(@r); # initialize
+ $self = bless {}, $class; # initialize
}
# ... or if bpi() is called as a method ...
@@ -1060,7 +1066,7 @@ sub bpi {
if ($selfref) { # bpi() called as instance method
return $self if $self -> modify('bpi');
} else { # bpi() called as class method
- $self = $class -> bzero(@r); # initialize
+ $self = bless {}, $class; # initialize
}
}
@@ -1509,14 +1515,21 @@ sub bneg {
# for +0 do not negate (to have always normalized +0). Does nothing for 'NaN'
$x->{sign} =~ tr/+-/-+/ unless ($x->{sign} eq '+' && $LIB->_is_zero($x->{_m}));
- $x;
+
+ return $downgrade -> new($x)
+ if defined($downgrade) && ($x -> is_int() || $x -> is_inf() || $x -> is_nan());
+ return $x;
}
sub bnorm {
# adjust m and e so that m is smallest possible
my ($class, $x) = ref($_[0]) ? (undef, $_[0]) : objectify(1, @_);
- return $x if $x->{sign} !~ /^[+-]$/; # inf, nan etc
+ # inf, nan etc
+ if ($x->{sign} !~ /^[+-]$/) {
+ return $downgrade->new($x) if defined $downgrade;
+ return $x;
+ }
my $zeros = $LIB->_zeros($x->{_m}); # correct for trailing zeros
if ($zeros != 0) {
@@ -1540,6 +1553,7 @@ sub bnorm {
if $LIB->_is_zero($x->{_m});
}
+ return $downgrade->new($x) if defined($downgrade) && $x->is_int();
$x;
}
@@ -1614,6 +1628,7 @@ sub badd {
# set up parameters
my ($class, $x, $y, @r) = (ref($_[0]), @_);
+
# objectify is costly, so avoid it
if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) {
($class, $x, $y, @r) = objectify(2, @_);
@@ -1622,17 +1637,25 @@ sub badd {
return $x if $x->modify('badd');
# inf and NaN handling
- if (($x->{sign} !~ /^[+-]$/) || ($y->{sign} !~ /^[+-]$/)) {
+ if ($x->{sign} !~ /^[+-]$/ || $y->{sign} !~ /^[+-]$/) {
+
# NaN first
- return $x->bnan() if (($x->{sign} eq $nan) || ($y->{sign} eq $nan));
+ if ($x->{sign} eq $nan || $y->{sign} eq $nan) {
+ $x->bnan();
+ }
+
# inf handling
- if (($x->{sign} =~ /^[+-]inf$/) && ($y->{sign} =~ /^[+-]inf$/)) {
+ elsif ($x->{sign} =~ /^[+-]inf$/ && $y->{sign} =~ /^[+-]inf$/) {
# +inf++inf or -inf+-inf => same, rest is NaN
- return $x if $x->{sign} eq $y->{sign};
- return $x->bnan();
+ $x->bnan() if $x->{sign} ne $y->{sign};
}
+
# +-inf + something => +inf; something +-inf => +-inf
- $x->{sign} = $y->{sign}, return $x if $y->{sign} =~ /^[+-]inf$/;
+ elsif ($y->{sign} =~ /^[+-]inf$/) {
+ $x->{sign} = $y->{sign};
+ }
+
+ return $downgrade->new($x, @r) if defined $downgrade;
return $x;
}
@@ -1641,55 +1664,61 @@ sub badd {
$r[3] = $y; # no push!
- # speed: no add for 0+y or x+0
- return $x->bround(@r) if $y->is_zero(); # x+0
- if ($x->is_zero()) # 0+y
- {
+ # for speed: no add for $x + 0
+ if ($y->is_zero()) {
+ $x->bround(@r);
+ }
+
+ # for speed: no add for 0 + $y
+ elsif ($x->is_zero()) {
# make copy, clobbering up x (modify in place!)
$x->{_e} = $LIB->_copy($y->{_e});
$x->{_es} = $y->{_es};
$x->{_m} = $LIB->_copy($y->{_m});
$x->{sign} = $y->{sign} || $nan;
- return $x->round(@r);
+ $x->round(@r);
}
- # take lower of the two e's and adapt m1 to it to match m2
- my $e = $y->{_e};
- $e = $LIB->_zero() if !defined $e; # if no BFLOAT?
- $e = $LIB->_copy($e); # make copy (didn't do it yet)
+ else {
- my $es;
+ # take lower of the two e's and adapt m1 to it to match m2
+ my $e = $y->{_e};
+ $e = $LIB->_zero() if !defined $e; # if no BFLOAT?
+ $e = $LIB->_copy($e); # make copy (didn't do it yet)
- ($e, $es) = _e_sub($e, $x->{_e}, $y->{_es} || '+', $x->{_es});
- #($e, $es) = $LIB -> _ssub($e, $y->{_es} || '+', $x->{_e}, $x->{_es});
+ my $es;
- my $add = $LIB->_copy($y->{_m});
+ ($e, $es) = _e_sub($e, $x->{_e}, $y->{_es} || '+', $x->{_es});
+ #($e, $es) = $LIB -> _ssub($e, $y->{_es} || '+', $x->{_e}, $x->{_es});
- if ($es eq '-') # < 0
- {
- $x->{_m} = $LIB->_lsft($x->{_m}, $e, 10);
- ($x->{_e}, $x->{_es}) = _e_add($x->{_e}, $e, $x->{_es}, $es);
- #$x->{_m} = $LIB->_lsft($x->{_m}, $e, 10);
- #($x->{_e}, $x->{_es}) = $LIB -> _sadd($x->{_e}, $x->{_es}, $e, $es);
+ my $add = $LIB->_copy($y->{_m});
- } elsif (!$LIB->_is_zero($e)) # > 0
- {
- $add = $LIB->_lsft($add, $e, 10);
- }
- # else: both e are the same, so just leave them
+ if ($es eq '-') { # < 0
+ $x->{_m} = $LIB->_lsft($x->{_m}, $e, 10);
+ ($x->{_e}, $x->{_es}) = _e_add($x->{_e}, $e, $x->{_es}, $es);
+ #$x->{_m} = $LIB->_lsft($x->{_m}, $e, 10);
+ #($x->{_e}, $x->{_es}) = $LIB -> _sadd($x->{_e}, $x->{_es}, $e, $es);
+ } elsif (!$LIB->_is_zero($e)) { # > 0
+ $add = $LIB->_lsft($add, $e, 10);
+ }
- if ($x->{sign} eq $y->{sign}) {
- # add
- $x->{_m} = $LIB->_add($x->{_m}, $add);
- } else {
- ($x->{_m}, $x->{sign}) =
- _e_add($x->{_m}, $add, $x->{sign}, $y->{sign});
- #($x->{_m}, $x->{sign}) =
- # $LIB -> _sadd($x->{_m}, $x->{sign}, $add, $y->{sign});
+ # else: both e are the same, so just leave them
+
+ if ($x->{sign} eq $y->{sign}) {
+ $x->{_m} = $LIB->_add($x->{_m}, $add);
+ } else {
+ ($x->{_m}, $x->{sign}) =
+ _e_add($x->{_m}, $add, $x->{sign}, $y->{sign});
+ #($x->{_m}, $x->{sign}) =
+ # $LIB -> _sadd($x->{_m}, $x->{sign}, $add, $y->{sign});
+ }
+
+ # delete trailing zeros, then round
+ $x->bnorm()->round(@r);
}
- # delete trailing zeros, then round
- $x->bnorm()->round(@r);
+ return $downgrade->new($x, @r) if defined($downgrade) && $x -> is_int();
+ return $x;
}
sub bsub {
@@ -1709,21 +1738,31 @@ sub bsub {
return $upgrade -> new($x) -> bsub($upgrade -> new($y), @r)
if defined $upgrade && (!$x -> isa($class) || !$y -> isa($class));
- return $x -> round(@r) if $y -> is_zero();
+ if ($y -> is_zero()) {
+ $x -> round(@r);
+ } else {
- # To correctly handle the lone special case $x -> bsub($x), we note the
- # sign of $x, then flip the sign from $y, and if the sign of $x did change,
- # too, then we caught the special case:
+ # To correctly handle the special case $x -> bsub($x), we note the sign
+ # of $x, then flip the sign of $y, and if the sign of $x changed too,
+ # then we know that $x and $y are the same object.
- my $xsign = $x -> {sign};
- $y -> {sign} =~ tr/+-/-+/; # does nothing for NaN
- if ($xsign ne $x -> {sign}) {
- # special case of $x -> bsub($x) results in 0
- return $x -> bzero(@r) if $xsign =~ /^[+-]$/;
- return $x -> bnan(); # NaN, -inf, +inf
+ my $xsign = $x -> {sign};
+ $y -> {sign} =~ tr/+-/-+/; # does nothing for NaN
+ if ($xsign ne $x -> {sign}) {
+ # special case of $x -> bsub($x) results in 0
+ if ($xsign =~ /^[+-]$/) {
+ $x -> bzero(@r);
+ } else {
+ $x -> bnan(); # NaN, -inf, +inf
+ }
+ return $downgrade->new($x, @r) if defined $downgrade;
+ return $x;
+ }
+ $x = $x -> badd($y, @r); # badd does not leave internal zeros
+ $y -> {sign} =~ tr/+-/-+/; # reset $y (does nothing for NaN)
}
- $x -> badd($y, @r); # badd does not leave internal zeros
- $y -> {sign} =~ tr/+-/-+/; # refix $y (does nothing for NaN)
+ return $downgrade->new($x, @r)
+ if defined($downgrade) && ($x->is_int() || $x->is_inf() || $x->is_nan());
$x; # already rounded by badd() or no rounding
}
@@ -1804,7 +1843,11 @@ sub bmuladd {
$x->{sign} = $x->{sign} ne $y->{sign} ? '-' : '+';
# z=inf handling (z=NaN handled above)
- $x->{sign} = $z->{sign}, return $x if $z->{sign} =~ /^[+-]inf$/;
+ if ($z->{sign} =~ /^[+-]inf$/) {
+ $x->{sign} = $z->{sign};
+ return $downgrade->new($x) if defined $downgrade;
+ return $x;
+ }
# take lower of the two e's and adapt m1 to it to match m2
my $e = $z->{_e};
@@ -1933,9 +1976,6 @@ sub bdiv {
# x == 0?
return wantarray ? ($x, $class->bzero()) : $x if $x->is_zero();
- # upgrade ?
- return $upgrade->bdiv($upgrade->new($x), $y, $a, $p, $r) if defined $upgrade;
-
# we need to limit the accuracy to protect against overflow
my $fallback = 0;
my (@params, $scale);
@@ -2034,8 +2074,14 @@ sub bdiv {
# clear a/p after round, since user did not request it
delete $rem->{_a}; delete $rem->{_p};
}
+ $x = $downgrade -> new($x)
+ if defined($downgrade) && $x -> is_int();
+ $rem = $downgrade -> new($rem)
+ if defined($downgrade) && $rem -> is_int();
return ($x, $rem);
}
+
+ $x = $downgrade -> new($x) if defined($downgrade) && $x -> is_int();
$x;
}
@@ -3633,24 +3679,42 @@ sub bround {
croak('bround() needs positive accuracy');
}
+ return $x if $x->modify('bround');
+
my ($scale, $mode) = $x->_scale_a(@_);
- return $x if !defined $scale || $x->modify('bround'); # no-op
+ if (!defined $scale) { # no-op
+ return $downgrade->new($x) if defined($downgrade)
+ && ($x->is_int() || $x->is_inf() || $x->is_nan());
+ return $x;
+ }
+
+ # Scale is now either $x->{_a}, $accuracy, or the input argument. Test
+ # whether $x already has lower accuracy, do nothing in this case but do
+ # round if the accuracy is the same, since a math operation might want to
+ # round a number with A=5 to 5 digits afterwards again
- # scale is now either $x->{_a}, $accuracy, or the user parameter
- # test whether $x already has lower accuracy, do nothing in this case
- # but do round if the accuracy is the same, since a math operation might
- # want to round a number with A=5 to 5 digits afterwards again
- return $x if defined $x->{_a} && $x->{_a} < $scale;
+ if (defined $x->{_a} && $x->{_a} < $scale) {
+ return $downgrade->new($x) if defined($downgrade)
+ && ($x->is_int() || $x->is_inf() || $x->is_nan());
+ return $x;
+ }
# scale < 0 makes no sense
# scale == 0 => keep all digits
# never round a +-inf, NaN
- return $x if ($scale <= 0) || $x->{sign} !~ /^[+-]$/;
+
+ if ($scale <= 0 || $x->{sign} !~ /^[+-]$/) {
+ return $downgrade->new($x) if defined($downgrade)
+ && ($x->is_int() || $x->is_inf() || $x->is_nan());
+ return $x;
+ }
# 1: never round a 0
# 2: if we should keep more digits than the mantissa has, do nothing
if ($x->is_zero() || $LIB->_len($x->{_m}) <= $scale) {
$x->{_a} = $scale if !defined $x->{_a} || $x->{_a} > $scale;
+ return $downgrade->new($x) if defined($downgrade)
+ && ($x->is_int() || $x->is_inf() || $x->is_nan());
return $x;
}
@@ -3661,6 +3725,8 @@ sub bround {
$x->{_m} = $m->{value}; # get our mantissa back
$x->{_a} = $scale; # remember rounding
delete $x->{_p}; # and clear P
+
+ # bnorm() downgrades if necessary, so no need to check whether to downgrade.
$x->bnorm(); # del trailing zeros gen. by bround()
}
@@ -3672,25 +3738,47 @@ sub bfround {
my $class = ref($x) || $x;
$x = $class->new(shift) if !ref($x);
+ return $x if $x->modify('bfround'); # no-op
+
my ($scale, $mode) = $x->_scale_p(@_);
- return $x if !defined $scale || $x->modify('bfround'); # no-op
+ if (!defined $scale) {
+ return $downgrade->new($x) if defined($downgrade)
+ && ($x->is_int() || $x->is_inf() || $x->is_nan());
+ return $x;
+ }
# never round a 0, +-inf, NaN
+
if ($x->is_zero()) {
$x->{_p} = $scale if !defined $x->{_p} || $x->{_p} < $scale; # -3 < -2
+ return $downgrade->new($x) if defined($downgrade)
+ && ($x->is_int() || $x->is_inf() || $x->is_nan());
+ return $x;
+ }
+
+ if ($x->{sign} !~ /^[+-]$/) {
+ return $downgrade->new($x) if defined($downgrade)
+ && ($x->is_int() || $x->is_inf() || $x->is_nan());
return $x;
}
- return $x if $x->{sign} !~ /^[+-]$/;
# don't round if x already has lower precision
- return $x if (defined $x->{_p} && $x->{_p} < 0 && $scale < $x->{_p});
+ if (defined $x->{_p} && $x->{_p} < 0 && $scale < $x->{_p}) {
+ return $downgrade->new($x) if defined($downgrade)
+ && ($x->is_int() || $x->is_inf() || $x->is_nan());
+ return $x;
+ }
$x->{_p} = $scale; # remember round in any case
delete $x->{_a}; # and clear A
if ($scale < 0) {
# round right from the '.'
- return $x if $x->{_es} eq '+'; # e >= 0 => nothing to round
+ if ($x->{_es} eq '+') { # e >= 0 => nothing to round
+ return $downgrade->new($x) if defined($downgrade)
+ && ($x->is_int() || $x->is_inf() || $x->is_nan());
+ return $x;
+ }
$scale = -$scale; # positive for simplicity
my $len = $LIB->_len($x->{_m}); # length of mantissa
@@ -3710,13 +3798,22 @@ sub bfround {
# 1.2345 12345e-4 5 0 4
# do not round after/right of the $dad
- return $x if $scale > $dad; # 0.123, scale >= 3 => exit
+
+ if ($scale > $dad) { # 0.123, scale >= 3 => exit
+ return $downgrade->new($x) if defined($downgrade)
+ && ($x->is_int() || $x->is_inf() || $x->is_nan());
+ return $x;
+ }
# round to zero if rounding inside the $zad, but not for last zero like:
# 0.0065, scale -2, round last '0' with following '65' (scale == zad case)
- return $x->bzero() if $scale < $zad;
- if ($scale == $zad) # for 0.006, scale -3 and trunc
- {
+ if ($scale < $zad) {
+ return $downgrade->new($x) if defined($downgrade)
+ && ($x->is_int() || $x->is_inf() || $x->is_nan());
+ return $x->bzero();
+ }
+
+ if ($scale == $zad) { # for 0.006, scale -3 and trunc
$scale = -$len;
} else {
# adjust round-point to be inside mantissa
@@ -3739,12 +3836,17 @@ sub bfround {
# should be the same, so treat it as this
$scale = 1 if $scale == 0;
# shortcut if already integer
- return $x if $scale == 1 && $dbt <= $dbd;
+ if ($scale == 1 && $dbt <= $dbd) {
+ return $downgrade->new($x) if defined($downgrade)
+ && ($x->is_int() || $x->is_inf() || $x->is_nan());
+ return $x;
+ }
# maximum digits before dot
++$dbd;
if ($scale > $dbd) {
# not enough digits before dot, so round to zero
+ return $downgrade->new($x) if defined($downgrade);
return $x->bzero;
} elsif ($scale == $dbd) {
# maximum
@@ -3753,66 +3855,81 @@ sub bfround {
$scale = $dbd - $scale;
}
}
+
# pass sign to bround for rounding modes '+inf' and '-inf'
my $m = bless { sign => $x->{sign}, value => $x->{_m} }, 'Math::BigInt';
$m->bround($scale, $mode);
$x->{_m} = $m->{value}; # get our mantissa back
+
+ # bnorm() downgrades if necessary, so no need to check whether to downgrade.
$x->bnorm();
}
sub bfloor {
# round towards minus infinity
- my ($class, $x, $a, $p, $r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
+ my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
return $x if $x->modify('bfloor');
- return $x if $x->{sign} !~ /^[+-]$/; # nan, +inf, -inf
- # if $x has digits after dot
- if ($x->{_es} eq '-') {
- $x->{_m} = $LIB->_rsft($x->{_m}, $x->{_e}, 10); # cut off digits after dot
- $x->{_e} = $LIB->_zero(); # trunc/norm
- $x->{_es} = '+'; # abs e
- $x->{_m} = $LIB->_inc($x->{_m}) if $x->{sign} eq '-'; # increment if negative
+ if ($x->{sign} =~ /^[+-]$/) {
+ # if $x has digits after dot, remove them
+ if ($x->{_es} eq '-') {
+ $x->{_m} = $LIB->_rsft($x->{_m}, $x->{_e}, 10);
+ $x->{_e} = $LIB->_zero();
+ $x->{_es} = '+';
+ # increment if negative
+ $x->{_m} = $LIB->_inc($x->{_m}) if $x->{sign} eq '-';
+ }
+ $x->round(@r);
}
- $x->round($a, $p, $r);
+ return $downgrade->new($x, @r) if defined($downgrade);
+ return $x;
}
sub bceil {
# round towards plus infinity
- my ($class, $x, $a, $p, $r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
+ my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
return $x if $x->modify('bceil');
- return $x if $x->{sign} !~ /^[+-]$/; # nan, +inf, -inf
- # if $x has digits after dot
- if ($x->{_es} eq '-') {
- $x->{_m} = $LIB->_rsft($x->{_m}, $x->{_e}, 10); # cut off digits after dot
- $x->{_e} = $LIB->_zero(); # trunc/norm
- $x->{_es} = '+'; # abs e
- if ($x->{sign} eq '+') {
- $x->{_m} = $LIB->_inc($x->{_m}); # increment if positive
- } else {
- $x->{sign} = '+' if $LIB->_is_zero($x->{_m}); # avoid -0
+ # if $x has digits after dot, remove them
+ if ($x->{sign} =~ /^[+-]$/) {
+ if ($x->{_es} eq '-') {
+ $x->{_m} = $LIB->_rsft($x->{_m}, $x->{_e}, 10);
+ $x->{_e} = $LIB->_zero();
+ $x->{_es} = '+';
+ if ($x->{sign} eq '+') {
+ $x->{_m} = $LIB->_inc($x->{_m}); # increment if positive
+ } else {
+ $x->{sign} = '+' if $LIB->_is_zero($x->{_m}); # avoid -0
+ }
}
+ $x->round(@r);
}
- $x->round($a, $p, $r);
+
+ return $downgrade->new($x, @r) if defined($downgrade);
+ return $x;
}
sub bint {
# round towards zero
- my ($class, $x, $a, $p, $r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
+ my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
return $x if $x->modify('bint');
- return $x if $x->{sign} !~ /^[+-]$/; # nan, +inf, -inf
- # if $x has digits after the decimal point
- if ($x->{_es} eq '-') {
- $x->{_m} = $LIB->_rsft($x->{_m}, $x->{_e}, 10); # cut off digits after dot
- $x->{_e} = $LIB->_zero(); # truncate/normalize
- $x->{_es} = '+'; # abs e
- $x->{sign} = '+' if $LIB->_is_zero($x->{_m}); # avoid -0
+ if ($x->{sign} =~ /^[+-]$/) {
+ # if $x has digits after the decimal point
+ if ($x->{_es} eq '-') {
+ $x->{_m} = $LIB->_rsft($x->{_m}, $x->{_e}, 10); # remove fraction part
+ $x->{_e} = $LIB->_zero(); # truncate/normalize
+ $x->{_es} = '+'; # abs e
+ $x->{sign} = '+' if $LIB->_is_zero($x->{_m}); # avoid -0
+ }
+ $x->round(@r);
}
- $x->round($a, $p, $r);
+
+ return $downgrade->new($x, @r) if defined($downgrade);
+ return $x;
}
###############################################################################
@@ -5234,7 +5351,7 @@ __END__
=head1 NAME
-Math::BigFloat - Arbitrary size floating point math package
+Math::BigFloat - arbitrary size floating point math package
=head1 SYNOPSIS
diff --git a/cpan/Math-BigInt/lib/Math/BigInt.pm b/cpan/Math-BigInt/lib/Math/BigInt.pm
index 0325742d38..489dbb6ce5 100644
--- a/cpan/Math-BigInt/lib/Math/BigInt.pm
+++ b/cpan/Math-BigInt/lib/Math/BigInt.pm
@@ -23,7 +23,8 @@ use warnings;
use Carp qw< carp croak >;
use Scalar::Util qw< blessed >;
-our $VERSION = '1.999829';
+our $VERSION = '1.999830';
+$VERSION =~ tr/_//d;
require Exporter;
our @ISA = qw(Exporter);
@@ -1642,6 +1643,7 @@ sub bdec {
#}
sub badd {
+
# add second arg (BINT or string) to first (BINT) (modifies first)
# return result as BINT
@@ -1708,7 +1710,7 @@ sub bsub {
return $x if $x -> modify('bsub');
- return $upgrade -> new($x) -> bsub($upgrade -> new($y), @r)
+ return $upgrade -> bsub($upgrade -> new($x), $upgrade -> new($y), @r)
if defined $upgrade && (!$x -> isa($class) || !$y -> isa($class));
return $x -> round(@r) if $y -> is_zero();
@@ -2813,7 +2815,7 @@ sub bsin {
return $x->bnan() if $x->{sign} !~ /^[+-]\z/; # -inf +inf or NaN => NaN
- return $upgrade->new($x)->bsin(@r) if defined $upgrade;
+ return $upgrade -> bsin($upgrade -> new($x, @r)) if defined $upgrade;
require Math::BigFloat;
# calculate the result and truncate it to integer
@@ -2833,11 +2835,11 @@ sub bcos {
return $x->bnan() if $x->{sign} !~ /^[+-]\z/; # -inf +inf or NaN => NaN
- return $upgrade->new($x)->bcos(@r) if defined $upgrade;
+ return $upgrade -> bcos($upgrade -> new($x), @r) if defined $upgrade;
require Math::BigFloat;
# calculate the result and truncate it to integer
- my $t = Math::BigFloat->new($x)->bcos(@r)->as_int();
+ my $t = Math::BigFloat -> bcos(Math::BigFloat -> new($x), @r) -> as_int();
$x->bone() if $t->is_one();
$x->bzero() if $t->is_zero();
@@ -4186,10 +4188,10 @@ sub objectify {
no strict 'refs';
- # What we upgrade to, if anything. Note that we need the whole chain of
- # upgrading, because we accept objects that go through multiple upgrades,
- # e.g., when Math::BigInt upgrades to Math::BigFloat which upgrades to
- # Math::BigRat. We delay getting the chain until we actually need it.
+ # What we upgrade to, if anything. Note that we need the whole upgrade
+ # chain, since there might be multiple levels of upgrading. E.g., class A
+ # upgrades to class B, which upgrades to class C. Delay getting the chain
+ # until we actually need it.
my @upg = ();
my $have_upgrade_chain = 0;
@@ -4218,12 +4220,14 @@ sub objectify {
next if $ref -> isa($a[0]);
- # Upgrading is OK, so skip further tests if the argument is upgraded.
+ # Upgrading is OK, so skip further tests if the argument is upgraded,
+ # but first get the whole upgrade chain if we haven't got it yet.
unless ($have_upgrade_chain) {
my $cls = $class;
my $upg = $cls -> upgrade();
while (defined $upg) {
+ last if $upg eq $cls;
push @upg, $upg;
$cls = $upg;
$upg = $cls -> upgrade();
@@ -5319,7 +5323,7 @@ __END__
=head1 NAME
-Math::BigInt - Arbitrary size integer/float math package
+Math::BigInt - arbitrary size integer math package
=head1 SYNOPSIS
@@ -5727,18 +5731,25 @@ Set/get the rounding mode.
Set/get the class for upgrading. When a computation might result in a
non-integer, the operands are upgraded to this class. This is used for instance
-by L<bignum>. The default is C<undef>, thus the following operation creates
-a Math::BigInt, not a Math::BigFloat:
+by L<bignum>. The default is C<undef>, i.e., no upgrading.
+
+ # with no upgrading
+ $x = Math::BigInt->new(12);
+ $y = Math::BigInt->new(5);
+ print $x / $y, "\n"; # 2 as a Math::BigInt
- my $i = Math::BigInt->new(123);
- my $f = Math::BigFloat->new('123.1');
+ # with upgrading to Math::BigFloat
+ Math::BigInt -> upgrade("Math::BigFloat");
+ print $x / $y, "\n"; # 2.4 as a Math::BigFloat
- print $i + $f, "\n"; # prints 246
+ # with upgrading to Math::BigRat (after loading Math::BigRat)
+ Math::BigInt -> upgrade("Math::BigRat");
+ print $x / $y, "\n"; # 12/5 as a Math::BigRat
=item downgrade()
-Set/get the class for downgrading. The default is C<undef>. Downgrading is not
-done by Math::BigInt.
+Set/get the class for downgrading. The default is C<undef>, i.e., no
+downgrading. Downgrading is not done by Math::BigInt.
=item modify()
@@ -5796,8 +5807,8 @@ parameters are marked as RW. The following parameters are supported.
$x = Math::BigInt->new($str,$A,$P,$R);
Creates a new Math::BigInt object from a scalar or another Math::BigInt object.
-The input is accepted as decimal, hexadecimal (with leading '0x') or binary
-(with leading '0b').
+The input is accepted as decimal, hexadecimal (with leading '0x'), octal (with
+leading ('0o') or binary (with leading '0b').
See L</Input> for more info on accepted input formats.
diff --git a/cpan/Math-BigInt/lib/Math/BigInt/Calc.pm b/cpan/Math-BigInt/lib/Math/BigInt/Calc.pm
index 3e39b71090..c6cb703ad7 100644
--- a/cpan/Math-BigInt/lib/Math/BigInt/Calc.pm
+++ b/cpan/Math-BigInt/lib/Math/BigInt/Calc.pm
@@ -7,7 +7,8 @@ use warnings;
use Carp qw< carp croak >;
use Math::BigInt::Lib;
-our $VERSION = '1.999829';
+our $VERSION = '1.999830';
+$VERSION =~ tr/_//d;
our @ISA = ('Math::BigInt::Lib');
diff --git a/cpan/Math-BigInt/lib/Math/BigInt/Lib.pm b/cpan/Math-BigInt/lib/Math/BigInt/Lib.pm
index 3e768ec0ad..55ba01059b 100644
--- a/cpan/Math-BigInt/lib/Math/BigInt/Lib.pm
+++ b/cpan/Math-BigInt/lib/Math/BigInt/Lib.pm
@@ -4,7 +4,8 @@ use 5.006001;
use strict;
use warnings;
-our $VERSION = '1.999829';
+our $VERSION = '1.999830';
+$VERSION =~ tr/_//d;
use Carp;
diff --git a/cpan/Math-BigInt/t/downgrade.t b/cpan/Math-BigInt/t/downgrade.t
index ea7c4b584e..c5f34402e4 100644
--- a/cpan/Math-BigInt/t/downgrade.t
+++ b/cpan/Math-BigInt/t/downgrade.t
@@ -1,40 +1,18 @@
# -*- mode: perl; -*-
+# Note that this does not test Math::BigFloat upgrading.
+
use strict;
use warnings;
-use Test::More tests => 15;
+use Test::More tests => 164;
use Math::BigInt upgrade => 'Math::BigFloat';
-use Math::BigFloat downgrade => 'Math::BigInt',
- upgrade => 'Math::BigInt';
-
-our ($CLASS, $EXPECTED_CLASS, $LIB);
-$CLASS = "Math::BigInt";
-$EXPECTED_CLASS = "Math::BigFloat";
-$LIB = "Math::BigInt::Calc"; # backend
+use Math::BigFloat downgrade => 'Math::BigInt';
# simplistic test for now
is(Math::BigFloat->downgrade(), 'Math::BigInt', 'Math::BigFloat->downgrade()');
-is(Math::BigFloat->upgrade(), 'Math::BigInt', 'Math::BigFloat->upgrade()');
-
-# these downgrade
-is(ref(Math::BigFloat->new("inf")), "Math::BigInt",
- qq|ref(Math::BigFloat->new("inf"))|);
-is(ref(Math::BigFloat->new("-inf")), "Math::BigInt",
- qq|ref(Math::BigFloat->new("-inf"))|);
-is(ref(Math::BigFloat->new("NaN")), "Math::BigInt",
- qq|ref(Math::BigFloat->new("NaN"))|);
-is(ref(Math::BigFloat->new("0")), "Math::BigInt",
- qq|ref(Math::BigFloat->new("0"))|);
-is(ref(Math::BigFloat->new("1")), "Math::BigInt",
- qq|ref(Math::BigFloat->new("1"))|);
-is(ref(Math::BigFloat->new("10")), "Math::BigInt",
- qq|ref(Math::BigFloat->new("10"))|);
-is(ref(Math::BigFloat->new("-10")), "Math::BigInt",
- qq|ref(Math::BigFloat->new("-10"))|);
-is(ref(Math::BigFloat->new("-10.0E1")), "Math::BigInt",
- qq|ref(Math::BigFloat->new("-10.0E1"))|);
+is(Math::BigInt->upgrade(), 'Math::BigFloat', 'Math::BigInt->upgrade()');
# bug until v1.67:
is(Math::BigFloat->new("0.2E0"), "0.2", qq|Math::BigFloat->new("0.2E0")|);
@@ -53,4 +31,462 @@ my $x = Math::BigFloat->new(2); # downgrades
is(Math::BigFloat->bpow("2", "0.5"), $x->bsqrt(),
qq|Math::BigFloat->bpow("2", "0.5")|);
+################################################################################
+# Verify that constructors downgrade when they should.
+
+note("Enable downgrading, and see if constructors downgrade");
+
+Math::BigFloat -> downgrade("Math::BigInt");
+
+# new()
+
+$x = Math::BigFloat -> new("0.5");
+cmp_ok($x, "==", 0.5);
+is(ref $x, "Math::BigFloat", "Creating a 0.5 does not downgrade");
+
+$x = Math::BigFloat -> new("4");
+cmp_ok($x, "==", 4, 'new("4")');
+is(ref $x, "Math::BigInt", "Creating a 4 downgrades to Math::BigInt");
+
+$x = Math::BigFloat -> new("0");
+cmp_ok($x, "==", 0, 'new("0")');
+is(ref $x, "Math::BigInt", "Creating a 0 downgrades to Math::BigInt");
+
+$x = Math::BigFloat -> new("1");
+cmp_ok($x, "==", 1, 'new("1")');
+is(ref $x, "Math::BigInt", "Creating a 1 downgrades to Math::BigInt");
+
+$x = Math::BigFloat -> new("Inf");
+cmp_ok($x, "==", "Inf", 'new("inf")');
+is(ref $x, "Math::BigInt", "Creating an Inf downgrades to Math::BigInt");
+
+$x = Math::BigFloat -> new("NaN");
+is($x, "NaN", 'new("NaN")');
+is(ref $x, "Math::BigInt", "Creating a NaN downgrades to Math::BigInt");
+
+# bzero()
+
+$x = Math::BigFloat -> bzero();
+cmp_ok($x, "==", 0, "bzero()");
+is(ref $x, "Math::BigInt", "Creating a 0 downgrades to Math::BigInt");
+
+# bone()
+
+$x = Math::BigFloat -> bone();
+cmp_ok($x, "==", 1, "bone()");
+is(ref $x, "Math::BigInt", "Creating a 1 downgrades to Math::BigInt");
+
+# binf()
+
+$x = Math::BigFloat -> binf();
+cmp_ok($x, "==", "Inf", "binf()");
+is(ref $x, "Math::BigInt", "Creating an Inf downgrades to Math::BigInt");
+
+# bnan()
+
+$x = Math::BigFloat -> bnan();
+is($x, "NaN", "bnan()");
+is(ref $x, "Math::BigInt", "Creating a NaN downgrades to Math::BigInt");
+
+# from_dec()
+
+$x = Math::BigFloat -> from_dec("3.14e2");
+cmp_ok($x, "==", 314, 'from_dec("3.14e2")');
+is(ref $x, "Math::BigInt", 'from_dec("3.14e2") downgrades to Math::BigInt');
+
+# from_hex()
+
+$x = Math::BigFloat -> from_hex("0x1.3ap+8");
+cmp_ok($x, "==", 314, 'from_hex("3.14e2")');
+is(ref $x, "Math::BigInt", 'from_hex("3.14e2") downgrades to Math::BigInt');
+
+# from_oct()
+
+$x = Math::BigFloat -> from_oct("0o1.164p+8");
+cmp_ok($x, "==", 314, 'from_oct("0o1.164p+8")');
+is(ref $x, "Math::BigInt", 'from_oct("0o1.164p+8") downgrades to Math::BigInt');
+
+# from_bin()
+
+$x = Math::BigFloat -> from_bin("0b1.0011101p+8");
+cmp_ok($x, "==", 314, 'from_bin("0b1.0011101p+8")');
+is(ref $x, "Math::BigInt",
+ 'from_bin("0b1.0011101p+8") downgrades to Math::BigInt');
+
+# from_ieee754()
+
+$x = Math::BigFloat -> from_ieee754("\x43\x9d\x00\x00", "binary32");
+cmp_ok($x, "==", 314, 'from_ieee754("\x43\x9d\x00\x00", "binary32")');
+is(ref $x, "Math::BigInt",
+ 'from_ieee754("\x43\x9d\x00\x00", "binary32") downgrades to Math::BigInt');
+
+note("Disable downgrading, and see if constructors downgrade");
+
+Math::BigFloat -> downgrade(undef);
+
+my $half = Math::BigFloat -> new("0.5");
+my $four = Math::BigFloat -> new("4");
+my $zero = Math::BigFloat -> bzero();
+my $inf = Math::BigFloat -> binf();
+my $nan = Math::BigFloat -> bnan();
+
+is(ref $half, "Math::BigFloat", "Creating a 0.5 does not downgrade");
+is(ref $four, "Math::BigFloat", "Creating a 4 does not downgrade");
+is(ref $zero, "Math::BigFloat", "Creating a 0 does not downgrade");
+is(ref $inf, "Math::BigFloat", "Creating an Inf does not downgrade");
+is(ref $nan, "Math::BigFloat", "Creating a NaN does not downgrade");
+
+################################################################################
+# Verify that other methods downgrade when they should.
+
+Math::BigFloat -> downgrade("Math::BigInt");
+
+# This shouldn't be necessary, but it is. Fixme!
+
+Math::BigInt -> upgrade(undef);
+
+# bneg()
+
+$x = $zero -> copy() -> bneg();
+cmp_ok($x, "==", 0, "-(0) = 0");
+is(ref($x), "Math::BigInt", "-(0) => Math::BigInt");
+
+$x = $four -> copy() -> bneg();
+cmp_ok($x, "==", -4, "-(4) = -4");
+is(ref($x), "Math::BigInt", "-(4) => Math::BigInt");
+
+$x = $inf -> copy() -> bneg();
+cmp_ok($x, "==", "-inf", "-(Inf) = -Inf");
+is(ref($x), "Math::BigInt", "-(Inf) => Math::BigInt");
+
+$x = $nan -> copy() -> bneg();
+is($x, "NaN", "-(NaN) = NaN");
+is(ref($x), "Math::BigInt", "-(NaN) => Math::BigInt");
+
+# bnorm()
+
+$x = $zero -> copy() -> bnorm();
+cmp_ok($x, "==", 0, "bnorm(0)");
+is(ref($x), "Math::BigInt", "bnorm(0) => Math::BigInt");
+
+$x = $four -> copy() -> bnorm();
+cmp_ok($x, "==", 4, "bnorm(4)");
+is(ref($x), "Math::BigInt", "bnorm(4) => Math::BigInt");
+
+$x = $inf -> copy() -> bnorm();
+cmp_ok($x, "==", "inf", "bnorm(Inf)");
+is(ref($x), "Math::BigInt", "bnorm(Inf) => Math::BigInt");
+
+$x = $nan -> copy() -> bnorm();
+is($x, "NaN", "bnorm(NaN)");
+is(ref($x), "Math::BigInt", "bnorm(NaN) => Math::BigInt");
+
+# binc()
+
+$x = $zero -> copy() -> binc();
+cmp_ok($x, "==", 1, "binc(0)");
+is(ref($x), "Math::BigInt", "binc(0) => Math::BigInt");
+
+$x = $four -> copy() -> binc();
+cmp_ok($x, "==", 5, "binc(4)");
+is(ref($x), "Math::BigInt", "binc(4) => Math::BigInt");
+
+$x = $inf -> copy() -> binc();
+cmp_ok($x, "==", "inf", "binc(Inf)");
+is(ref($x), "Math::BigInt", "binc(Inf) => Math::BigInt");
+
+$x = $nan -> copy() -> binc();
+is($x, "NaN", "binc(NaN)");
+is(ref($x), "Math::BigInt", "binc(NaN) => Math::BigInt");
+
+# bdec()
+
+$x = $zero -> copy() -> bdec();
+cmp_ok($x, "==", -1, "bdec(0)");
+is(ref($x), "Math::BigInt", "bdec(0) => Math::BigInt");
+
+$x = $four -> copy() -> bdec();
+cmp_ok($x, "==", 3, "bdec(4)");
+is(ref($x), "Math::BigInt", "bdec(4) => Math::BigInt");
+
+$x = $inf -> copy() -> bdec();
+cmp_ok($x, "==", "inf", "bdec(Inf)");
+is(ref($x), "Math::BigInt", "bdec(Inf) => Math::BigInt");
+
+$x = $nan -> copy() -> bdec();
+is($x, "NaN", "bdec(NaN)");
+is(ref($x), "Math::BigInt", "bdec(NaN) => Math::BigInt");
+
+# badd()
+
+$x = $half -> copy() -> badd($nan);
+is($x, "NaN", "0.5 + NaN = NaN");
+is(ref($x), "Math::BigInt", "0.5 + NaN => Math::BigInt");
+
+$x = $half -> copy() -> badd($inf);
+cmp_ok($x, "==", "+Inf", "0.5 + Inf = Inf");
+is(ref($x), "Math::BigInt", "2.5 + Inf => Math::BigInt");
+
+$x = $half -> copy() -> badd($half);
+cmp_ok($x, "==", 1, "0.5 + 0.5 = 1");
+is(ref($x), "Math::BigInt", "0.5 + 0.5 => Math::BigInt");
+
+$x = $half -> copy() -> badd($half -> copy() -> bneg());
+cmp_ok($x, "==", 0, "0.5 + -0.5 = 0");
+is(ref($x), "Math::BigInt", "0.5 + -0.5 => Math::BigInt");
+
+$x = $four -> copy() -> badd($zero);
+cmp_ok($x, "==", 4, "4 + 0 = 4");
+is(ref($x), "Math::BigInt", "4 + 0 => Math::BigInt");
+
+$x = $zero -> copy() -> badd($four);
+cmp_ok($x, "==", 4, "0 + 4 = 4");
+is(ref($x), "Math::BigInt", "0 + 4 => Math::BigInt");
+
+$x = $inf -> copy() -> badd($four);
+cmp_ok($x, "==", "+Inf", "Inf + 4 = Inf");
+is(ref($x), "Math::BigInt", "Inf + 4 => Math::BigInt");
+
+$x = $nan -> copy() -> badd($four);
+is($x, "NaN", "NaN + 4 = NaN");
+is(ref($x), "Math::BigInt", "NaN + 4 => Math::BigInt");
+
+# bsub()
+
+$x = $half -> copy() -> bsub($nan);
+is($x, "NaN", "0.5 - NaN = NaN");
+is(ref($x), "Math::BigInt", "0.5 - NaN => Math::BigInt");
+
+$x = $half -> copy() -> bsub($inf);
+cmp_ok($x, "==", "-Inf", "2.5 - Inf = -Inf");
+is(ref($x), "Math::BigInt", "2.5 - Inf => Math::BigInt");
+
+$x = $half -> copy() -> bsub($half);
+cmp_ok($x, "==", 0, "0.5 + 0.5 = 0");
+is(ref($x), "Math::BigInt", "0.5 - 0.5 => Math::BigInt");
+
+$x = $half -> copy() -> bsub($half -> copy() -> bneg());
+cmp_ok($x, "==", 1, "0.5 - -0.5 = 1");
+is(ref($x), "Math::BigInt", "0.5 - -0.5 => Math::BigInt");
+
+$x = $four -> copy() -> bsub($zero);
+cmp_ok($x, "==", 4, "4 - 0 = 4");
+is(ref($x), "Math::BigInt", "4 - 0 => Math::BigInt");
+
+$x = $zero -> copy() -> bsub($four);
+cmp_ok($x, "==", -4, "0 - 4 = -4");
+is(ref($x), "Math::BigInt", "0 - 4 => Math::BigInt");
+
+$x = $inf -> copy() -> bsub($four);
+cmp_ok($x, "==", "Inf", "Inf - 4 = Inf");
+is(ref($x), "Math::BigInt", "Inf - 4 => Math::BigInt");
+
+$x = $nan -> copy() -> bsub($four);
+is($x, "NaN", "NaN - 4 = NaN");
+is(ref($x), "Math::BigInt", "NaN - 4 => Math::BigInt");
+
+# bmul()
+
+$x = $zero -> copy() -> bmul($four);
+cmp_ok($x, "==", 0, "bmul(0, 4) = 0");
+is(ref($x), "Math::BigInt", "bmul(0, 4) => Math::BigInt");
+
+$x = $four -> copy() -> bmul($four);
+cmp_ok($x, "==", 16, "bmul(4, 4) = 16");
+is(ref($x), "Math::BigInt", "bmul(4, 4) => Math::BigInt");
+
+$x = $inf -> copy() -> bmul($four);
+cmp_ok($x, "==", "inf", "bmul(Inf, 4) = Inf");
+is(ref($x), "Math::BigInt", "bmul(Inf, 4) => Math::BigInt");
+
+$x = $nan -> copy() -> bmul($four);
+is($x, "NaN", "bmul(NaN, 4) = NaN");
+is(ref($x), "Math::BigInt", "bmul(NaN, 4) => Math::BigInt");
+
+$x = $four -> copy() -> bmul("0.5");
+cmp_ok($x, "==", 2, "bmul(4, 0.5) = 2");
+is(ref($x), "Math::BigInt", "bmul(4, 0.5) => Math::BigInt");
+
+# bmuladd()
+
+$x = $zero -> copy() -> bmuladd($four, $four);
+cmp_ok($x, "==", 4, "bmuladd(0, 4, 4) = 4");
+is(ref($x), "Math::BigInt", "bmuladd(0, 4, 4) => Math::BigInt");
+
+$x = $four -> copy() -> bmuladd($four, $four);
+cmp_ok($x, "==", 20, "bmuladd(4, 4, 4) = 20");
+is(ref($x), "Math::BigInt", "bmuladd(4, 4, 4) => Math::BigInt");
+
+$x = $four -> copy() -> bmuladd($four, $inf);
+cmp_ok($x, "==", "inf", "bmuladd(4, 4, Inf) = Inf");
+is(ref($x), "Math::BigInt", "bmuladd(4, 4, Inf) => Math::BigInt");
+
+$x = $inf -> copy() -> bmuladd($four, $four);
+cmp_ok($x, "==", "inf", "bmuladd(Inf, 4, 4) = Inf");
+is(ref($x), "Math::BigInt", "bmuladd(Inf, 4, 4) => Math::BigInt");
+
+$x = $inf -> copy() -> bmuladd($four, $four);
+cmp_ok($x, "==", "inf", "bmuladd(Inf, 4, 4) = Inf");
+is(ref($x), "Math::BigInt", "bmuladd(Inf, 4, 4) => Math::BigInt");
+
+$x = $nan -> copy() -> bmuladd($four, $four);
+is($x, "NaN", "bmuladd(NaN, 4, 4) = NaN");
+is(ref($x), "Math::BigInt", "bmuladd(NaN, 4, 4) => Math::BigInt");
+
+$x = $four -> copy() -> bmuladd("0.5", $four);
+cmp_ok($x, "==", 6, "bmuladd(4, 0.5, 4) = 6");
+is(ref($x), "Math::BigInt", "bmuladd(4, 0.5, 4) => Math::BigInt");
+
+# bdiv()
+
+# bmod()
+
+# bmodpow()
+
+# bpow()
+
+# blog()
+
+# bexp()
+
+# bnok()
+
+# bsin()
+
+# bcos()
+
+# batan()
+
+# batan()
+
+# bsqrt()
+
+# broot()
+
+# bfac()
+
+# bdfac()
+
+# btfac()
+
+# bmfac()
+
+# blsft()
+
+# brsft()
+
+# band()
+
+# bior()
+
+# bxor()
+
+# bnot()
+
+# bround()
+
+# Add tests for rounding a non-integer to an integer. Fixme!
+
+$x = $zero -> copy() -> bround();
+cmp_ok($x, "==", 0, "bround(0)");
+is(ref($x), "Math::BigInt", "bround(0) => Math::BigInt");
+
+$x = $four -> copy() -> bround();
+cmp_ok($x, "==", 4, "bround(4)");
+is(ref($x), "Math::BigInt", "bround(4) => Math::BigInt");
+
+$x = $inf -> copy() -> bround();
+cmp_ok($x, "==", "inf", "bround(Inf)");
+is(ref($x), "Math::BigInt", "bround(Inf) => Math::BigInt");
+
+$x = $nan -> copy() -> bround();
+is($x, "NaN", "bround(NaN)");
+is(ref($x), "Math::BigInt", "bround(NaN) => Math::BigInt");
+
+# bfround()
+
+# Add tests for rounding a non-integer to an integer. Fixme!
+
+$x = $zero -> copy() -> bfround();
+cmp_ok($x, "==", 0, "bfround(0)");
+is(ref($x), "Math::BigInt", "bfround(0) => Math::BigInt");
+
+$x = $four -> copy() -> bfround();
+cmp_ok($x, "==", 4, "bfround(4)");
+is(ref($x), "Math::BigInt", "bfround(4) => Math::BigInt");
+
+$x = $inf -> copy() -> bfround();
+cmp_ok($x, "==", "inf", "bfround(Inf)");
+is(ref($x), "Math::BigInt", "bfround(Inf) => Math::BigInt");
+
+$x = $nan -> copy() -> bfround();
+is($x, "NaN", "bfround(NaN)");
+is(ref($x), "Math::BigInt", "bfround(NaN) => Math::BigInt");
+
+# bfloor()
+
+$x = $half -> copy() -> bfloor();
+cmp_ok($x, "==", 0, "bfloor(0)");
+is(ref($x), "Math::BigInt", "bfloor(0) => Math::BigInt");
+
+$x = $inf -> copy() -> bfloor();
+cmp_ok($x, "==", "Inf", "bfloor(Inf)");
+is(ref($x), "Math::BigInt", "bfloor(Inf) => Math::BigInt");
+
+$x = $nan -> copy() -> bfloor();
+is($x, "NaN", "bfloor(NaN)");
+is(ref($x), "Math::BigInt", "bfloor(NaN) => Math::BigInt");
+
+# bceil()
+
+$x = $half -> copy() -> bceil();
+cmp_ok($x, "==", 1, "bceil(0)");
+is(ref($x), "Math::BigInt", "bceil(0) => Math::BigInt");
+
+$x = $inf -> copy() -> bceil();
+cmp_ok($x, "==", "Inf", "bceil(Inf)");
+is(ref($x), "Math::BigInt", "bceil(Inf) => Math::BigInt");
+
+$x = $nan -> copy() -> bceil();
+is($x, "NaN", "bceil(NaN)");
+is(ref($x), "Math::BigInt", "bceil(NaN) => Math::BigInt");
+
+# bint()
+
+$x = $half -> copy() -> bint();
+cmp_ok($x, "==", 0, "bint(0)");
+is(ref($x), "Math::BigInt", "bint(0) => Math::BigInt");
+
+$x = $inf -> copy() -> bint();
+cmp_ok($x, "==", "Inf", "bint(Inf)");
+is(ref($x), "Math::BigInt", "bint(Inf) => Math::BigInt");
+
+$x = $nan -> copy() -> bint();
+is($x, "NaN", "bint(NaN)");
+is(ref($x), "Math::BigInt", "bint(NaN) => Math::BigInt");
+
+# bgcd()
+
+# blcm()
+
+# mantissa() ?
+
+# exponent() ?
+
+# parts() ?
+
+# sparts()
+
+# nparts()
+
+# eparts()
+
+# dparts()
+
+# fparts()
+
+# numerator()
+
+# denominator()
+
#require 'upgrade.inc'; # all tests here for sharing
diff --git a/cpan/Math-BigInt/t/upgrade.t b/cpan/Math-BigInt/t/upgrade.t
index fa72e8da2a..94f7e8a0dc 100644
--- a/cpan/Math-BigInt/t/upgrade.t
+++ b/cpan/Math-BigInt/t/upgrade.t
@@ -4,11 +4,29 @@ use strict;
use warnings;
use Test::More tests => 2134 # tests in require'd file
- + 2; # tests in this file
+ + 6; # tests in this file
-use Math::BigInt upgrade => 'Math::BigFloat';
+use Math::BigInt;
use Math::BigFloat;
+my $x = Math::BigInt -> new(9);
+my $y = Math::BigInt -> new(4);
+
+# Without upgrading.
+
+my $zi = $x / $y;
+cmp_ok($zi, "==", 2, "9/4 = 2 without upgrading");
+is(ref($zi), "Math::BigInt", "9/4 gives a Math::BigInt without upgrading");
+
+# With upgrading.
+
+Math::BigInt -> upgrade("Math::BigFloat");
+my $zf = $x / $y;
+cmp_ok($zf, "==", 2.25, "9/4 = 2.25 with upgrading");
+is(ref($zf), "Math::BigFloat", "9/4 gives a Math::BigFloat with upgrading");
+
+# Other tests.
+
our ($CLASS, $EXPECTED_CLASS, $LIB);
$CLASS = "Math::BigInt";
$EXPECTED_CLASS = "Math::BigFloat";