diff options
author | Hugo van der Sanden <hv@crypt.org> | 2022-04-12 19:30:53 +0100 |
---|---|---|
committer | Ricardo Signes <rjbs@semiotic.systems> | 2022-04-17 10:18:13 -0400 |
commit | 8dec64698880d15d36aa3ca539b11827e014b51e (patch) | |
tree | 6ef5812a22ee603818f18aa6af224bf8cf8c4fb7 /cpan/Math-BigInt | |
parent | a5f79404890330b9ec94ceec5a976b34e7720e37 (diff) | |
download | perl-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.pm | 365 | ||||
-rw-r--r-- | cpan/Math-BigInt/lib/Math/BigInt.pm | 51 | ||||
-rw-r--r-- | cpan/Math-BigInt/lib/Math/BigInt/Calc.pm | 3 | ||||
-rw-r--r-- | cpan/Math-BigInt/lib/Math/BigInt/Lib.pm | 3 | ||||
-rw-r--r-- | cpan/Math-BigInt/t/downgrade.t | 490 | ||||
-rw-r--r-- | cpan/Math-BigInt/t/upgrade.t | 22 |
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"; |