New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[PATCH] Correct bdiv() and bmod() in Math::BigInt and Math::BigFloat #14650
Comments
From @pjacklamCorrect bdiv() and bmod() in Math::BigInt and Math::BigFloat - The POD documentation, as well as the comments in the code, say that - Clearer POD documentation for the bdiv() and bmod() methods. - Changed test files to match corrected behaviour. - Removed some duplicated tests. - This patch fixes CPAN RT 66633 and CPAN RT 92953. |
From @pjacklam0001-Correct-bdiv-and-bmod-in-Math-BigInt-and-Math-BigFlo.patchFrom 494435bf42409d6e166d8cbe9555a8df90b19c2c Mon Sep 17 00:00:00 2001
From: pjacklam <pjacklam@gmail.com>
Date: Tue, 14 Apr 2015 15:20:14 +0200
Subject: [PATCH] Correct bdiv() and bmod() in Math::BigInt and Math::BigFloat
- The POD documentation, as well as the comments in the code, say that
$x->bdiv($y) in list context should return quotient $q and remainder $r
so that $x = $q * $y + $r, and that the remainder (modulo) $r should
correspond to Perl's % operator as well as the bmod() method. This has
not been the actual behaviour. This patch fixes this.
- Clearer POD documentation for the bdiv() and bmod() methods.
- Changed test files to match corrected behaviour.
- Removed some duplicated tests.
---
dist/Math-BigInt/lib/Math/BigFloat.pm | 168 ++++++++++++---
dist/Math-BigInt/lib/Math/BigInt.pm | 305 +++++++++++++++++++---------
dist/Math-BigInt/lib/Math/BigInt/Calc.pm | 2 +-
dist/Math-BigInt/lib/Math/BigInt/CalcEmu.pm | 2 +-
dist/Math-BigInt/t/bare_mbf.t | 2 +-
dist/Math-BigInt/t/bare_mbi.t | 2 +-
dist/Math-BigInt/t/bigfltpm.inc | 18 +-
dist/Math-BigInt/t/bigfltpm.t | 2 +-
dist/Math-BigInt/t/bigintpm.inc | 58 +++---
dist/Math-BigInt/t/bigintpm.t | 2 +-
dist/Math-BigInt/t/inf_nan.t | 93 ++++++++-
dist/Math-BigInt/t/sub_mbf.t | 2 +-
dist/Math-BigInt/t/sub_mbi.t | 2 +-
dist/Math-BigInt/t/upgrade.inc | 39 ++--
dist/Math-BigInt/t/upgrade.t | 2 +-
dist/Math-BigInt/t/with_sub.t | 2 +-
16 files changed, 495 insertions(+), 206 deletions(-)
diff --git a/dist/Math-BigInt/lib/Math/BigFloat.pm b/dist/Math-BigInt/lib/Math/BigFloat.pm
index 1c31496..209bede 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.9997';
+$VERSION = '1.999701';
require 5.006002;
require Exporter;
@@ -1776,7 +1776,7 @@ sub bmuladd
sub bdiv
{
# (dividend: BFLOAT or num_str, divisor: BFLOAT or num_str) return
- # (BFLOAT,BFLOAT) (quo,rem) or BFLOAT (only rem)
+ # (BFLOAT, BFLOAT) (quo, rem) or BFLOAT (only quo)
# set up parameters
my ($self,$x,$y,$a,$p,$r) = (ref($_[0]),@_);
@@ -1788,10 +1788,80 @@ sub bdiv
return $x if $x->modify('bdiv');
- return $self->_div_inf($x,$y)
- if (($x->{sign} !~ /^[+-]$/) || ($y->{sign} !~ /^[+-]$/) || $y->is_zero());
+ my $wantarray = wantarray; # call only once
- # x== 0 # also: or y == 1 or y == -1
+ # At least one argument is NaN. This is handled the same way as in
+ # Math::BigInt -> bdiv().
+
+ if ($x -> is_nan() || $y -> is_nan()) {
+ return $wantarray ? ($x -> bnan(), $self -> bnan()) : $x -> bnan();
+ }
+
+ # Divide by zero and modulo zero. This is handled the same way as in
+ # Math::BigInt -> bdiv(). See the comment in the code for Math::BigInt ->
+ # bdiv() for further details.
+
+ if ($y -> is_zero()) {
+ my ($quo, $rem);
+ if ($wantarray) {
+ $rem = $x -> copy();
+ }
+ if ($x -> is_zero()) {
+ $quo = $x -> bnan();
+ } else {
+ $quo = $x -> binf($x -> {sign});
+ }
+ return $wantarray ? ($quo, $rem) : $quo;
+ }
+
+ # Numerator (dividend) is +/-inf. This is handled the same way as in
+ # Math::BigInt -> bdiv(). See the comment in the code for Math::BigInt ->
+ # bdiv() for further details.
+
+ if ($x -> is_inf()) {
+ my ($quo, $rem);
+ $rem = $self -> bnan() if $wantarray;
+ if ($y -> is_inf()) {
+ $quo = $x -> bnan();
+ } else {
+ my $sign = $x -> bcmp(0) == $y -> bcmp(0) ? '+' : '-';
+ $quo = $x -> binf($sign);
+ }
+ return $wantarray ? ($quo, $rem) : $quo;
+ }
+
+ # Denominator (divisor) is +/-inf. This is handled the same way as in
+ # Math::BigInt -> bdiv(), with one exception: In scalar context,
+ # Math::BigFloat does true division (although rounded), not floored division
+ # (F-division), so a finite number divided by +/-inf is always zero. See the
+ # comment in the code for Math::BigInt -> bdiv() for further details.
+
+ if ($y -> is_inf()) {
+ my ($quo, $rem);
+ if ($wantarray) {
+ if ($x -> is_zero() || $x -> bcmp(0) == $y -> bcmp(0)) {
+ $rem = $x -> copy();
+ $quo = $x -> bzero();
+ } else {
+ $rem = $self -> binf($y -> {sign});
+ $quo = $x -> bone('-');
+ }
+ return ($quo, $rem);
+ } else {
+ if ($y -> is_inf()) {
+ if ($x -> is_nan() || $x -> is_inf()) {
+ return $x -> bnan();
+ } else {
+ return $x -> bzero();
+ }
+ }
+ }
+ }
+
+ # At this point, both the numerator and denominator are finite numbers, and
+ # the denominator (divisor) is non-zero.
+
+ # x == 0?
return wantarray ? ($x,$self->bzero()) : $x if $x->is_zero();
# upgrade ?
@@ -1805,33 +1875,30 @@ sub bdiv
return $x if $x->is_nan(); # error in _find_round_parameters?
# no rounding at all, so must use fallback
- if (scalar @params == 0)
+ if (scalar @params == 0)
{
# simulate old behaviour
$params[0] = $self->div_scale(); # and round to it as accuracy
$scale = $params[0]+4; # at least four more for proper round
$params[2] = $r; # round mode by caller or undef
$fallback = 1; # to clear a/p afterwards
- }
- else
- {
+ } else {
# the 4 below is empirical, and there might be cases where it is not
# enough...
$scale = abs($params[0] || $params[1]) + 4; # take whatever is defined
}
- my $rem; $rem = $self->bzero() if wantarray;
+ my $rem;
+ $rem = $self -> bzero() if wantarray;
$y = $self->new($y) unless $y->isa('Math::BigFloat');
- my $lx = $MBI->_len($x->{_m}); my $ly = $MBI->_len($y->{_m});
+ my $lx = $MBI -> _len($x->{_m}); my $ly = $MBI -> _len($y->{_m});
$scale = $lx if $lx > $scale;
$scale = $ly if $ly > $scale;
my $diff = $ly - $lx;
$scale += $diff if $diff > 0; # if lx << ly, but not if ly << lx!
- # already handled inf/NaN/-inf above:
-
# check that $y is not 1 nor -1 and cache the result:
my $y_not_one = !($MBI->_is_zero($y->{_e}) && $MBI->_is_one($y->{_m}));
@@ -1899,7 +1966,7 @@ sub bdiv
{
if ($y_not_one)
{
- $x -> bint();
+ $x -> bfloor();
$rem->bmod($y,@params); # copy already done
}
if ($fallback)
@@ -1926,34 +1993,54 @@ sub bmod
return $x if $x->modify('bmod');
- # handle NaN, inf, -inf
- if (($x->{sign} !~ /^[+-]$/) || ($y->{sign} !~ /^[+-]$/))
- {
- my ($d,$re) = $self->SUPER::_div_inf($x,$y);
- $x->{sign} = $re->{sign};
- $x->{_e} = $re->{_e};
- $x->{_m} = $re->{_m};
- return $x->round($a,$p,$r,$y);
+ # At least one argument is NaN. This is handled the same way as in
+ # Math::BigInt -> bmod().
+
+ if ($x -> is_nan() || $y -> is_nan()) {
+ return $x -> bnan();
}
- if ($y->is_zero())
- {
- return $x->bnan() if $x->is_zero();
+
+ # Modulo zero. This is handled the same way as in Math::BigInt -> bmod().
+
+ if ($y -> is_zero()) {
return $x;
}
+ # Numerator (dividend) is +/-inf. This is handled the same way as in
+ # Math::BigInt -> bmod().
+
+ if ($x -> is_inf()) {
+ return $x -> bnan();
+ }
+
+ # Denominator (divisor) is +/-inf. This is handled the same way as in
+ # Math::BigInt -> bmod().
+
+ if ($y -> is_inf()) {
+ if ($x -> is_zero() || $x -> bcmp(0) == $y -> bcmp(0)) {
+ return $x;
+ } else {
+ return $x -> binf($y -> sign());
+ }
+ }
+
return $x->bzero() if $x->is_zero()
|| ($x->is_int() &&
# check that $y == +1 or $y == -1:
($MBI->_is_zero($y->{_e}) && $MBI->_is_one($y->{_m})));
my $cmp = $x->bacmp($y); # equal or $x < $y?
- return $x->bzero($a,$p) if $cmp == 0; # $x == $y => result 0
+ if ($cmp == 0) { # $x == $y => result 0
+ return $x -> bzero($a, $p);
+ }
# only $y of the operands negative?
- my $neg = 0; $neg = 1 if $x->{sign} ne $y->{sign};
+ my $neg = $x->{sign} ne $y->{sign} ? 1 : 0;
$x->{sign} = $y->{sign}; # calc sign first
- return $x->round($a,$p,$r) if $cmp < 0 && $neg == 0; # $x < $y => result $x
+ if ($cmp < 0 && $neg == 0) { # $x < $y => result $x
+ return $x -> round($a, $p, $r);
+ }
my $ym = $MBI->_copy($y->{_m});
@@ -1996,7 +2083,7 @@ sub bmod
$x->{sign} = '+' if $MBI->_is_zero($x->{_m}); # fix sign for -0
$x->bnorm();
- if ($neg != 0) # one of them negative => correct in place
+ if ($neg != 0 && ! $x -> is_zero()) # one of them negative => correct in place
{
my $r = $y - $x;
$x->{_m} = $r->{_m};
@@ -4027,8 +4114,8 @@ Actual math is done by using the class defined with C<< with => Class; >>
(which defaults to BigInts) to represent the mantissa and exponent.
The sign C</^[+-]$/> is stored separately. The string 'NaN' is used to
-represent the result when input arguments are not numbers, as well as
-the result of dividing by zero.
+represent the result when input arguments are not numbers, and 'inf' and
+'-inf' are used to represent positive and negative infinity, respectively.
=head2 mantissa(), exponent() and parts()
@@ -4208,6 +4295,25 @@ Note: You probably want to use L</accuracy()> instead. With L</accuracy()> you
set the number of digits each result should have, with L</precision()> you
set the place where to round!
+=item bdiv()
+
+ $q = $x->bdiv($y);
+ ($q, $r) = $x->bdiv($y);
+
+In scalar context, divides $x by $y and returns the result to the given or
+default accuracy/precision. In list context, does floored division
+(F-division), returning an integer $q and a remainder $r so that $x = $q * $y +
+$r. The remainer (modulo) is equal to what is returned by C<$x->bmod($y)>.
+
+=item bmod()
+
+ $x->bmod($y);
+
+Returns $x modulo $y. When $x is finite, and $y is finite and non-zero, the
+result is identical to the remainder after floored division (F-division). If,
+in addition, both $x and $y are integers, the result is identical to the result
+from Perl's % operator.
+
=item bexp()
$x->bexp($accuracy); # calculate e ** X
diff --git a/dist/Math-BigInt/lib/Math/BigInt.pm b/dist/Math-BigInt/lib/Math/BigInt.pm
index 62f1be9..2381c26 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.9997';
+$VERSION = '1.999701';
@ISA = qw(Exporter);
@EXPORT_OK = qw(objectify bgcd blcm);
@@ -1657,103 +1657,175 @@ sub bmuladd
$x->round(@r);
}
-sub _div_inf
+sub bdiv
{
- # helper function that handles +-inf cases for bdiv()/bmod() to reuse code
- my ($self,$x,$y) = @_;
- # NaN if x == NaN or y == NaN or x==y==0
- return wantarray ? ($x->bnan(),$self->bnan()) : $x->bnan()
- if (($x->is_nan() || $y->is_nan()) ||
- ($x->is_zero() && $y->is_zero()));
+ # This does floored division, where the quotient is floored toward negative
+ # infinity and the remainder has the same sign as the divisor.
- # +-inf / +-inf == NaN, remainder also NaN
- if (($x->{sign} =~ /^[+-]inf$/) && ($y->{sign} =~ /^[+-]inf$/))
- {
- return wantarray ? ($x->bnan(),$self->bnan()) : $x->bnan();
+ # Set up parameters.
+ my ($self,$x,$y,@r) = (ref($_[0]),@_);
+
+ # objectify() is costly, so avoid it if we can.
+ if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) {
+ ($self,$x,$y,@r) = objectify(2,@_);
}
- # x / +-inf => 0, remainder x (works even if x == 0)
- if ($y->{sign} =~ /^[+-]inf$/)
- {
- my $t = $x->copy(); # bzero clobbers up $x
- return wantarray ? ($x->bzero(),$t) : $x->bzero()
+
+ return $x if $x->modify('bdiv');
+
+ my $wantarray = wantarray; # call only once
+
+ # At least one argument is NaN. Return NaN for both quotient and the
+ # modulo/remainder.
+
+ if ($x -> is_nan() || $y -> is_nan()) {
+ return $wantarray ? ($x -> bnan(), $self -> bnan()) : $x -> bnan();
}
- # 5 / 0 => +inf, -6 / 0 => -inf
- # +inf / 0 = inf, inf, and -inf / 0 => -inf, -inf
- # exception: -8 / 0 has remainder -8, not 8
- # exception: -inf / 0 has remainder -inf, not inf
- if ($y->is_zero())
- {
- # +-inf / 0 => special case for -inf
- return wantarray ? ($x,$x->copy()) : $x if $x->is_inf();
- if (!$x->is_zero() && !$x->is_inf())
- {
- my $t = $x->copy(); # binf clobbers up $x
- return wantarray ?
- ($x->binf($x->{sign}),$t) : $x->binf($x->{sign})
+ # Divide by zero and modulo zero.
+ #
+ # Division: Use the common convention that x / 0 is inf with the same sign
+ # as x, except when x = 0, where we return NaN. This is also what earlier
+ # versions did.
+ #
+ # Modulo: In modular arithmetic, the congruence relation z = x (mod y)
+ # means that there is some integer k such that z - x = k y. If y = 0, we
+ # get z - x = 0 or z = x. This is also what earlier versions did, except
+ # that 0 % 0 returned NaN.
+ #
+ # inf / 0 = inf inf % 0 = inf
+ # 5 / 0 = inf 5 % 0 = 5
+ # 0 / 0 = NaN 0 % 0 = 0 (before: NaN)
+ # -5 / 0 = -inf -5 % 0 = -5
+ # -inf / 0 = -inf -inf % 0 = -inf
+
+ if ($y -> is_zero()) {
+ my ($quo, $rem);
+ if ($wantarray) {
+ $rem = $x -> copy();
+ }
+ if ($x -> is_zero()) {
+ $quo = $x -> bnan();
+ } else {
+ $quo = $x -> binf($x -> {sign});
+ }
+ return $wantarray ? ($quo, $rem) : $quo;
+ }
+
+ # Numerator (dividend) is +/-inf, and denominator is finite and non-zero.
+ # The divide by zero cases are covered above. In all of the cases listed
+ # below we return the same as core Perl.
+ #
+ # inf / -inf = NaN inf % -inf = NaN
+ # inf / -5 = -inf inf % -5 = NaN (before: 0)
+ # inf / 5 = inf inf % 5 = NaN (before: 0)
+ # inf / inf = NaN inf % inf = NaN
+ #
+ # -inf / -inf = NaN -inf % -inf = NaN
+ # -inf / -5 = inf -inf % -5 = NaN (before: 0)
+ # -inf / 5 = -inf -inf % 5 = NaN (before: 0)
+ # -inf / inf = NaN -inf % inf = NaN
+
+ if ($x -> is_inf()) {
+ my ($quo, $rem);
+ $rem = $self -> bnan() if $wantarray;
+ if ($y -> is_inf()) {
+ $quo = $x -> bnan();
+ } else {
+ my $sign = $x -> bcmp(0) == $y -> bcmp(0) ? '+' : '-';
+ $quo = $x -> binf($sign);
}
+ return $wantarray ? ($quo, $rem) : $quo;
}
- # last case: +-inf / ordinary number
- my $sign = '+inf';
- $sign = '-inf' if substr($x->{sign},0,1) ne $y->{sign};
- $x->{sign} = $sign;
- return wantarray ? ($x,$self->bzero()) : $x;
+ # Denominator (divisor) is +/-inf. The cases when the numerator is +/-inf
+ # are covered above. In the modulo cases (in the right column) we return
+ # the same as core Perl, which does floored division, so for consistency we
+ # also do floored division in the division cases (in the left column).
+ #
+ # -5 / inf = -1 (before: 0) -5 % inf = inf (before: -5)
+ # 0 / inf = 0 0 % inf = 0
+ # 5 / inf = 0 5 % inf = 5
+ #
+ # -5 / -inf = 0 -5 % -inf = -5
+ # 0 / -inf = 0 0 % -inf = 0
+ # 5 / -inf = -1 (before: 0) 5 % -inf = -inf (before: 5)
+
+ if ($y -> is_inf()) {
+ my ($quo, $rem);
+ if ($x -> is_zero() || $x -> bcmp(0) == $y -> bcmp(0)) {
+ $rem = $x -> copy() if $wantarray;
+ $quo = $x -> bzero();
+ } else {
+ $rem = $self -> binf($y -> {sign}) if $wantarray;
+ $quo = $x -> bone('-');
+ }
+ return $wantarray ? ($quo, $rem) : $quo;
}
-sub bdiv
- {
- # (dividend: BINT or num_str, divisor: BINT or num_str) return
- # (BINT,BINT) (quo,rem) or BINT (only rem)
-
- # set up parameters
- my ($self,$x,$y,@r) = (ref($_[0]),@_);
- # objectify is costly, so avoid it
- if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
- {
- ($self,$x,$y,@r) = objectify(2,@_);
- }
-
- return $x if $x->modify('bdiv');
-
- return $self->_div_inf($x,$y)
- if (($x->{sign} !~ /^[+-]$/) || ($y->{sign} !~ /^[+-]$/) || $y->is_zero());
+ # At this point, both the numerator and denominator are finite numbers, and
+ # the denominator (divisor) is non-zero.
return $upgrade->bdiv($upgrade->new($x),$upgrade->new($y),@r)
if defined $upgrade;
$r[3] = $y; # no push!
- # calc new sign and in case $y == +/- 1, return $x
- my $xsign = $x->{sign}; # keep
- $x->{sign} = ($x->{sign} ne $y->{sign} ? '-' : '+');
+ # Inialize remainder.
- if (wantarray)
- {
my $rem = $self->bzero();
+
+ # Are both operands the same object, i.e., like $x -> bdiv($x)?
+ # If so, flipping the sign of $y also flips the sign of $x.
+
+ my $xsign = $x->{sign};
+ my $ysign = $y->{sign};
+
+ $y->{sign} =~ tr/+-/-+/; # Flip the sign of $y, and see ...
+ my $same = $xsign ne $x->{sign}; # ... if that changed the sign of $x.
+ $y->{sign} = $ysign; # Re-insert the original sign.
+
+ if ($same) {
+ $x -> bone();
+ } else {
($x->{value},$rem->{value}) = $CALC->_div($x->{value},$y->{value});
- $x->{sign} = '+' if $CALC->_is_zero($x->{value});
- $rem->{_a} = $x->{_a};
- $rem->{_p} = $x->{_p};
+
+ if ($CALC -> _is_zero($rem->{value})) {
+ if ($xsign eq $ysign || $CALC -> _is_zero($x->{value})) {
+ $x->{sign} = '+';
+ } else {
+ $x->{sign} = '-';
+ }
+ } else {
+ if ($xsign eq $ysign) {
+ $x->{sign} = '+';
+ } else {
+ if ($xsign eq '+') {
+ $x -> badd(1);
+ } else {
+ $x -> bsub(1);
+ }
+ $x->{sign} = '-';
+ }
+ }
+ }
+
$x->round(@r);
- if (! $CALC->_is_zero($rem->{value}))
- {
- $rem->{sign} = $y->{sign};
- $rem = $y->copy()->bsub($rem) if $xsign ne $y->{sign}; # one of them '-'
+
+ if ($wantarray) {
+ unless ($CALC -> _is_zero($rem->{value})) {
+ if ($xsign ne $ysign) {
+ $rem = $y -> copy() -> babs() -> bsub($rem);
}
- else
- {
- $rem->{sign} = '+'; # do not leave -0
+ $rem->{sign} = $ysign;
}
+ $rem->{_a} = $x->{_a};
+ $rem->{_p} = $x->{_p};
$rem->round(@r);
return ($x,$rem);
}
- $x->{value} = $CALC->_div($x->{value},$y->{value});
- $x->{sign} = '+' if $CALC->_is_zero($x->{value});
-
- $x->round(@r);
+ return $x;
}
###############################################################################
@@ -1761,11 +1833,14 @@ sub bdiv
sub bmod
{
- # modulus (or remainder)
- # (BINT or num_str, BINT or num_str) return BINT
- # set up parameters
+ # This is the remainder after floored division, where the quotient is
+ # floored toward negative infinity and the remainder has the same sign as
+ # the divisor.
+
+ # Set up parameters.
my ($self,$x,$y,@r) = (ref($_[0]),@_);
+
# objectify is costly, so avoid it
if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
{
@@ -1774,35 +1849,62 @@ sub bmod
return $x if $x->modify('bmod');
$r[3] = $y; # no push!
- if (($x->{sign} !~ /^[+-]$/) || ($y->{sign} !~ /^[+-]$/) || $y->is_zero())
- {
- my ($d,$r) = $self->_div_inf($x,$y);
- $x->{sign} = $r->{sign};
- $x->{value} = $r->{value};
- return $x->round(@r);
+
+ # At least one argument is NaN.
+
+ if ($x -> is_nan() || $y -> is_nan()) {
+ return $x -> bnan();
+ }
+
+ # Modulo zero. See documentation for bdiv().
+
+ if ($y -> is_zero()) {
+ return $x;
+ }
+
+ # Numerator (dividend) is +/-inf.
+
+ if ($x -> is_inf()) {
+ return $x -> bnan();
}
- # calc new sign and in case $y == +/- 1, return $x
+ # Denominator (divisor) is +/-inf.
+
+ if ($y -> is_inf()) {
+ if ($x -> is_zero() || $x -> bcmp(0) == $y -> bcmp(0)) {
+ return $x;
+ } else {
+ return $x -> binf($y -> sign());
+ }
+ }
+
+ # Calc new sign and in case $y == +/- 1, return $x.
+
$x->{value} = $CALC->_mod($x->{value},$y->{value});
- if (!$CALC->_is_zero($x->{value}))
+ if ($CALC -> _is_zero($x->{value}))
+ {
+ $x->{sign} = '+'; # do not leave -0
+ }
+ else
{
$x->{value} = $CALC->_sub($y->{value},$x->{value},1) # $y-$x
if ($x->{sign} ne $y->{sign});
$x->{sign} = $y->{sign};
}
- else
- {
- $x->{sign} = '+'; # do not leave -0
- }
+
$x->round(@r);
}
sub bmodinv
{
- # Return modular multiplicative inverse: z is the modular inverse of x (mod
- # y) if and only if x*z (mod y) = 1 (mod y). If the modulus y is larger than
- # one, x and z are relative primes (i.e., their greatest common divisor is
- # one).
+ # Return modular multiplicative inverse:
+ #
+ # z is the modular inverse of x (mod y) if and only if
+ #
+ # x*z ��� 1 (mod y)
+ #
+ # If the modulus y is larger than one, x and z are relative primes (i.e.,
+ # their greatest common divisor is one).
#
# If no modular multiplicative inverse exists, NaN is returned.
@@ -1896,8 +1998,17 @@ sub bmodpow
return $num->bnan() if ($num->{sign} =~ /NaN|inf/ || # NaN, -inf, +inf
$exp->{sign} =~ /NaN|inf/ || # NaN, -inf, +inf
- $mod->{sign} =~ /NaN|inf/ || # NaN, -inf, +inf
- $mod->is_zero());
+ $mod->{sign} =~ /NaN|inf/); # NaN, -inf, +inf
+
+ # Modulo zero. See documentation for Math::BigInt's bmod() method.
+
+ if ($mod -> is_zero()) {
+ if ($num -> is_zero()) {
+ return $self -> bnan();
+ } else {
+ return $num -> copy();
+ }
+ }
# Compute 'a (mod m)', ignoring the signs on 'a' and 'm'. If the resulting
# value is zero, the output is also zero, regardless of the signs on 'a' and
@@ -3927,12 +4038,20 @@ This method was added in v1.87 of Math::BigInt (June 2007).
=item bdiv()
$x->bdiv($y); # divide, set $x to quotient
- # return (quo,rem) or quo if scalar
+
+Returns $x divided by $y. In list context, does floored division (F-division),
+where the quotient is the greatest integer less than or equal to the quotient
+of the two operands. Consequently, the remainder is either zero or has the same
+sign as the second operand. In scalar context, only the quotient is returned.
=item bmod()
$x->bmod($y); # modulus (x % y)
+Returns $x modulo $y. When $x is finite, and $y is finite and non-zero, the
+result is identical to the remainder after floored division (F-division), i.e.,
+identical to the result from Perl's % operator.
+
=item bmodinv()
$x->bmodinv($mod); # modular multiplicative inverse
diff --git a/dist/Math-BigInt/lib/Math/BigInt/Calc.pm b/dist/Math-BigInt/lib/Math/BigInt/Calc.pm
index d511bab..ce9bf3a 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; # do not use warnings for older Perls
-our $VERSION = '1.9997';
+our $VERSION = '1.999701';
# Package to store unsigned big integers in decimal and do math with them
diff --git a/dist/Math-BigInt/lib/Math/BigInt/CalcEmu.pm b/dist/Math-BigInt/lib/Math/BigInt/CalcEmu.pm
index 9bf3e07..0ff9dcc 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; # do not use warnings for older Perls
use vars qw/$VERSION/;
-$VERSION = '1.9997';
+$VERSION = '1.999701';
package Math::BigInt;
diff --git a/dist/Math-BigInt/t/bare_mbf.t b/dist/Math-BigInt/t/bare_mbf.t
index 49ba8cb..8f37270 100644
--- a/dist/Math-BigInt/t/bare_mbf.t
+++ b/dist/Math-BigInt/t/bare_mbf.t
@@ -1,7 +1,7 @@
#!/usr/bin/perl -w
use strict;
-use Test::More tests => 2338;
+use Test::More tests => 2336;
BEGIN { unshift @INC, 't'; }
diff --git a/dist/Math-BigInt/t/bare_mbi.t b/dist/Math-BigInt/t/bare_mbi.t
index eaedbf7..8aedf43 100644
--- a/dist/Math-BigInt/t/bare_mbi.t
+++ b/dist/Math-BigInt/t/bare_mbi.t
@@ -1,7 +1,7 @@
#!/usr/bin/perl -w
use strict;
-use Test::More tests => 3651;
+use Test::More tests => 3649;
BEGIN { unshift @INC, 't'; }
diff --git a/dist/Math-BigInt/t/bigfltpm.inc b/dist/Math-BigInt/t/bigfltpm.inc
index 1528e48..2ffeafa 100644
--- a/dist/Math-BigInt/t/bigfltpm.inc
+++ b/dist/Math-BigInt/t/bigfltpm.inc
@@ -1404,7 +1404,7 @@ NaNmul:-inf:NaN
6:120:720
10:10000:100000
&fdiv-list
-0:0:NaN,NaN
+0:0:NaN,0
0:1:0,0
9:4:2,1
9:5:1,4
@@ -1499,13 +1499,13 @@ $div_scale = 40
0:inf:0
0:-inf:0
5:inf:5
-5:-inf:5
--5:inf:-5
+5:-inf:-inf
+-5:inf:inf
-5:-inf:-5
-inf:5:0
--inf:5:0
-inf:-5:0
--inf:-5:0
+inf:5:NaN
+-inf:5:NaN
+inf:-5:NaN
+-inf:-5:NaN
5:5:0
-5:-5:0
inf:inf:NaN
@@ -1514,14 +1514,12 @@ inf:inf:NaN
inf:-inf:NaN
8:0:8
inf:0:inf
-# exceptions to remainder rule
-inf:0:-inf
-8:0:-8
-0:0:NaN
+0:0:0
abc:abc:NaN
abc:1:abc:NaN
1:abc:NaN
-0:0:NaN
0:1:0
1:0:1
0:-1:0
diff --git a/dist/Math-BigInt/t/bigfltpm.t b/dist/Math-BigInt/t/bigfltpm.t
index de3c80e..6f6e598 100644
--- a/dist/Math-BigInt/t/bigfltpm.t
+++ b/dist/Math-BigInt/t/bigfltpm.t
@@ -1,7 +1,7 @@
#!/usr/bin/perl -w
use strict;
-use Test::More tests => 2338
+use Test::More tests => 2336
+ 5; # own tests
diff --git a/dist/Math-BigInt/t/bigintpm.inc b/dist/Math-BigInt/t/bigintpm.inc
index c3e815c..1481502 100644
--- a/dist/Math-BigInt/t/bigintpm.inc
+++ b/dist/Math-BigInt/t/bigintpm.inc
@@ -1548,19 +1548,19 @@ NaNmul:-inf:NaN
5:8:0,5
0:8:0,0
11:2:5,1
-11:-2:-5,-1
--11:2:-5,1
+11:-2:-6,-1
+-11:2:-6,1
# see table in documentation in MBI
0:inf:0,0
0:-inf:0,0
5:inf:0,5
-5:-inf:0,5
--5:inf:0,-5
+5:-inf:-1,-inf
+-5:inf:-1,inf
-5:-inf:0,-5
-inf:5:inf,0
--inf:5:-inf,0
-inf:-5:-inf,0
--inf:-5:inf,0
+inf:5:inf,NaN
+-inf:5:-inf,NaN
+inf:-5:-inf,NaN
+-inf:-5:inf,NaN
5:5:1,0
-5:-5:1,0
inf:inf:NaN,NaN
@@ -1572,7 +1572,7 @@ inf:0:inf,inf
# exceptions to remainder rule
-8:0:-inf,-8
-inf:0:-inf,-inf
-0:0:NaN,NaN
+0:0:NaN,0
# test the shortcut in Calc if @$x == @$yorg
1234567812345678:123456712345678:10,688888898
12345671234567:1234561234567:10,58888897
@@ -1615,8 +1615,8 @@ abc:1:NaN
0:inf:0
0:-inf:0
5:inf:0
-5:-inf:0
--5:inf:0
+5:-inf:-1
+-5:inf:-1
-5:-inf:0
inf:5:inf
-inf:5:-inf
@@ -1635,8 +1635,8 @@ inf:0:inf
0:0:NaN
11:2:5
-11:-2:5
--11:2:-5
-11:-2:-5
+-11:2:-6
+11:-2:-6
0:1:0
0:-1:0
1:1:1
@@ -1670,17 +1670,17 @@ inf:0:inf
999999999999999:99999:10000100001
+1111088889:99999:11111
-5:-3:1
--5:3:-1
+-5:3:-2
4:3:1
-4:-3:-1
+4:-3:-2
1:3:0
-1:-3:0
+1:-3:-1
-2:-3:0
--2:3:0
+-2:3:-1
8:3:2
--8:3:-2
-14:-3:-4
--14:3:-4
+-8:3:-3
+14:-3:-5
+-14:3:-5
-14:-3:4
14:3:4
# bug in Calc with '99999' vs $BASE-1
@@ -1774,7 +1774,7 @@ abc:abc:5:NaN
5:5:abc:NaN
5:abc:5:NaN
abc:5:5:NaN
-3:5:0:NaN
+3:5:0:3
# bmodpow Expected results
0:0:2:1
1:0:2:1
@@ -1940,13 +1940,13 @@ inf:5:13:NaN
0:inf:0
0:-inf:0
5:inf:5
-5:-inf:5
--5:inf:-5
+5:-inf:-inf
+-5:inf:inf
-5:-inf:-5
-inf:5:0
--inf:5:0
-inf:-5:0
--inf:-5:0
+inf:5:NaN
+-inf:5:NaN
+inf:-5:NaN
+-inf:-5:NaN
5:5:0
-5:-5:0
inf:inf:NaN
@@ -1955,14 +1955,12 @@ inf:inf:NaN
inf:-inf:NaN
8:0:8
inf:0:inf
-# exceptions to remainder rule
-inf:0:-inf
-8:0:-8
-0:0:NaN
+0:0:0
abc:abc:NaN
abc:1:abc:NaN
1:abc:NaN
-0:0:NaN
0:1:0
1:0:1
0:-1:0
diff --git a/dist/Math-BigInt/t/bigintpm.t b/dist/Math-BigInt/t/bigintpm.t
index 8f009ec..a03710e 100644
--- a/dist/Math-BigInt/t/bigintpm.t
+++ b/dist/Math-BigInt/t/bigintpm.t
@@ -1,7 +1,7 @@
#!/usr/bin/perl -w
use strict;
-use Test::More tests => 3651 + 6;
+use Test::More tests => 3649 + 6;
use Math::BigInt lib => 'Calc';
diff --git a/dist/Math-BigInt/t/inf_nan.t b/dist/Math-BigInt/t/inf_nan.t
index b3f61ba..270689b 100644
--- a/dist/Math-BigInt/t/inf_nan.t
+++ b/dist/Math-BigInt/t/inf_nan.t
@@ -18,10 +18,10 @@ use Math::BigFloat;
use Math::BigInt::Subclass;
use Math::BigFloat::Subclass;
-my @classes =
- qw/Math::BigInt Math::BigFloat
- Math::BigInt::Subclass Math::BigFloat::Subclass
- /;
+my @biclasses =
+ qw/ Math::BigInt Math::BigInt::Subclass /;
+my @bfclasses =
+ qw/ Math::BigFloat Math::BigFloat::Subclass /;
my (@args,$x,$y,$z);
@@ -77,7 +77,7 @@ foreach (qw/
/)
{
@args = split /:/,$_;
- for my $class (@classes)
+ for my $class (@biclasses, @bfclasses)
{
$x = $class->new($args[0]);
$y = $class->new($args[1]);
@@ -141,7 +141,7 @@ foreach (qw/
/)
{
@args = split /:/,$_;
- for my $class (@classes)
+ for my $class (@biclasses, @bfclasses)
{
$x = $class->new($args[0]);
$y = $class->new($args[1]);
@@ -205,7 +205,7 @@ foreach (qw/
/)
{
@args = split /:/,$_;
- for my $class (@classes)
+ for my $class (@biclasses, @bfclasses)
{
$x = $class->new($args[0]);
$y = $class->new($args[1]);
@@ -224,7 +224,7 @@ foreach (qw/
-1:-inf:0
-0:-inf:0
0:-inf:-0
- 1:-inf:-0
+ 1:-inf:-1
inf:-inf:NaN
NaN:-inf:NaN
@@ -253,7 +253,7 @@ foreach (qw/
NaN:1:NaN
-inf:inf:NaN
- -1:inf:-0
+ -1:inf:-1
-0:inf:-0
0:inf:0
1:inf:0
@@ -270,7 +270,7 @@ foreach (qw/
/)
{
@args = split /:/,$_;
- for my $class (@classes)
+ for my $class (@biclasses, @bfclasses)
{
$x = $class->new($args[0]);
$y = $class->new($args[1]);
@@ -280,9 +280,11 @@ foreach (qw/
my $tmod = $t->copy();
# bdiv in scalar context
+ unless ($class =~ /^Math::BigFloat/) {
my $r = $x->bdiv($y);
is($x->bstr(),$args[2],"x $class $args[0] / $args[1]");
is($r->bstr(),$args[2],"r $class $args[0] / $args[1]");
+ }
# bmod and bdiv in list context
my ($d,$rem) = $t->bdiv($y);
@@ -302,6 +304,75 @@ foreach (qw/
}
}
+# /
+foreach (qw/
+ -inf:-inf:NaN
+ -1:-inf:0
+ -0:-inf:0
+ 0:-inf:-0
+ 1:-inf:-0
+ inf:-inf:NaN
+ NaN:-inf:NaN
+
+ -inf:-1:inf
+ -1:-1:1
+ -0:-1:0
+ 0:-1:-0
+ 1:-1:-1
+ inf:-1:-inf
+ NaN:-1:NaN
+
+ -inf:0:-inf
+ -1:0:-inf
+ -0:0:NaN
+ 0:0:NaN
+ 1:0:inf
+ inf:0:inf
+ NaN:0:NaN
+
+ -inf:1:-inf
+ -1:1:-1
+ -0:1:-0
+ 0:1:0
+ 1:1:1
+ inf:1:inf
+ NaN:1:NaN
+
+ -inf:inf:NaN
+ -1:inf:-0
+ -0:inf:-0
+ 0:inf:0
+ 1:inf:0
+ inf:inf:NaN
+ NaN:inf:NaN
+
+ -inf:NaN:NaN
+ -1:NaN:NaN
+ -0:NaN:NaN
+ 0:NaN:NaN
+ 1:NaN:NaN
+ inf:NaN:NaN
+ NaN:NaN:NaN
+ /)
+ {
+ @args = split /:/,$_;
+ for my $class (@bfclasses)
+ {
+ $x = $class->new($args[0]);
+ $y = $class->new($args[1]);
+ $args[2] = '0' if $args[2] eq '-0'; # BigInt/Float hasn't got -0
+
+ my $t = $x->copy();
+ my $tmod = $t->copy();
+
+ # bdiv in scalar context
+ my $r = $x->bdiv($y);
+ is($x->bstr(),$args[2],"x $class $args[0] / $args[1]");
+ is($r->bstr(),$args[2],"r $class $args[0] / $args[1]");
+
+ }
+ }
+
#############################################################################
# overloaded comparisons
@@ -309,7 +380,7 @@ foreach (qw/
# mind what NaN actually is, see [perl #33106].
#
-#foreach my $c (@classes)
+#foreach my $c (@biclasses, @bfclasses)
# {
# my $x = $c->bnan();
# my $y = $c->bnan(); # test with two different objects, too
diff --git a/dist/Math-BigInt/t/sub_mbf.t b/dist/Math-BigInt/t/sub_mbf.t
index 061b06a..28252b4 100644
--- a/dist/Math-BigInt/t/sub_mbf.t
+++ b/dist/Math-BigInt/t/sub_mbf.t
@@ -1,7 +1,7 @@
#!/usr/bin/perl -w
use strict;
-use Test::More tests => 2338
+use Test::More tests => 2336
+ 6; # + our own tests
diff --git a/dist/Math-BigInt/t/sub_mbi.t b/dist/Math-BigInt/t/sub_mbi.t
index e23389d..b8e0a02 100644
--- a/dist/Math-BigInt/t/sub_mbi.t
+++ b/dist/Math-BigInt/t/sub_mbi.t
@@ -1,7 +1,7 @@
#!/usr/bin/perl -w
use strict;
-use Test::More tests => 3651
+use Test::More tests => 3649
+ 5; # +5 own tests
BEGIN { unshift @INC, 't'; }
diff --git a/dist/Math-BigInt/t/upgrade.inc b/dist/Math-BigInt/t/upgrade.inc
index ef0a6ea..16ca05e 100644
--- a/dist/Math-BigInt/t/upgrade.inc
+++ b/dist/Math-BigInt/t/upgrade.inc
@@ -841,19 +841,19 @@ NaNmul:-inf:NaN
5:8:0,5
0:8:0,0
11:2:5,1
-11:-2:-5,-1
--11:2:-5,1
+11:-2:-6,-1
+-11:2:-6,1
# see table in documentation in MBI
0:inf:0,0
0:-inf:0,0
5:inf:0,5
-5:-inf:0,5
--5:inf:0,-5
+5:-inf:-1,-inf
+-5:inf:-1,inf
-5:-inf:0,-5
-inf:5:inf,0
--inf:5:-inf,0
-inf:-5:-inf,0
--inf:-5:inf,0
+inf:5:inf,NaN
+-inf:5:-inf,NaN
+inf:-5:-inf,NaN
+-inf:-5:inf,NaN
5:5:1,0
-5:-5:1,0
inf:inf:NaN,NaN
@@ -865,7 +865,7 @@ inf:0:inf,inf
# exceptions to remainder rule
-8:0:-inf,-8
-inf:0:-inf,-inf
-0:0:NaN,NaN
+0:0:NaN,0
&bdiv
abc:abc:NaN
abc:1:NaN
@@ -875,8 +875,8 @@ abc:1:NaN
0:inf:0
0:-inf:0
5:inf:0
-5:-inf:0
--5:inf:0
+5:-inf:-1
+-5:inf:-1
-5:-inf:0
inf:5:inf
-inf:5:-inf
@@ -892,7 +892,6 @@ inf:-inf:NaN
inf:0:inf
-8:0:-inf
-inf:0:-inf
-0:0:NaN
11:2:5.5^
-11:-2:5.5^
-11:2:-5.5^
@@ -950,13 +949,13 @@ inf:0:inf
0:inf:0
0:-inf:0
5:inf:5
-5:-inf:5
--5:inf:-5
+5:-inf:-inf
+-5:inf:inf
-5:-inf:-5
-inf:5:0
--inf:5:0
-inf:-5:0
--inf:-5:0
+inf:5:NaN
+-inf:5:NaN
+inf:-5:NaN
+-inf:-5:NaN
5:5:0
-5:-5:0
inf:inf:NaN
@@ -965,14 +964,12 @@ inf:inf:NaN
inf:-inf:NaN
8:0:8
inf:0:inf
-# exceptions to remainder rule
-inf:0:-inf
-8:0:-8
-0:0:NaN
+0:0:0
abc:abc:NaN
abc:1:abc:NaN
1:abc:NaN
-0:0:NaN
0:1:0
1:0:1
0:-1:0
diff --git a/dist/Math-BigInt/t/upgrade.t b/dist/Math-BigInt/t/upgrade.t
index ab09f53..d209879 100644
--- a/dist/Math-BigInt/t/upgrade.t
+++ b/dist/Math-BigInt/t/upgrade.t
@@ -1,7 +1,7 @@
#!/usr/bin/perl -w
use strict;
-use Test::More tests => 2128
+use Test::More tests => 2124
+ 2; # our own tests
use Math::BigInt upgrade => 'Math::BigFloat';
diff --git a/dist/Math-BigInt/t/with_sub.t b/dist/Math-BigInt/t/with_sub.t
index 6f5d72d..48dfa30 100644
--- a/dist/Math-BigInt/t/with_sub.t
+++ b/dist/Math-BigInt/t/with_sub.t
@@ -3,7 +3,7 @@
# Test use Math::BigFloat with => 'Math::BigInt::SomeSubclass';
use strict;
-use Test::More tests => 2338 + 1;
+use Test::More tests => 2336 + 1;
use Math::BigFloat with => 'Math::BigInt::Subclass', lib => 'Calc';
--
2.1.4
|
From @jkeenanOn Tue Apr 14 07:28:11 2015, pjacklam wrote:
Smoke-testing in branch smoke-me/jkeenan/124300-124303-Math-BigIntRat -- |
The RT System itself - Status changed from 'new' to 'open' |
From @tonycozOn Tue Apr 14 07:28:11 2015, pjacklam wrote:
From the patch header: From 494435bf42409d6e166d8cbe9555a8df90b19c2c Mon Sep 17 00:00:00 2001 This doesn't match the author used in your previous patches, which was: Peter John Acklam <pjacklam@online.no> Did you want to switch to that new email address? The name part of the author is different too. The same is true of the #124303 patch. Tony |
From @pjacklamYes, please change the name and e-mail address in both patches to Peter John Acklam <pjacklam@online.no> I will try to avoid this mistake again. Peter 2015-04-15 3:55 GMT+02:00 Tony Cook via RT <perlbug-followup@perl.org>:
|
From @tonycozOn Tue Apr 14 18:55:03 2015, tonyc wrote:
Here's the corrected patch, if anyone beats me to it after blead is re-opened. Also in my post-5.22 branch. Tony |
From @tonycoz0001-Correct-bdiv-and-bmod-in-Math-BigInt-and-Math-BigFlo.patchFrom 7c32b40e0df335cdb7d2330c95017061d63a6708 Mon Sep 17 00:00:00 2001
From: Peter John Acklam <pjacklam@online.no>
Date: Tue, 14 Apr 2015 15:20:14 +0200
Subject: Correct bdiv() and bmod() in Math::BigInt and Math::BigFloat
- The POD documentation, as well as the comments in the code, say that
$x->bdiv($y) in list context should return quotient $q and remainder $r
so that $x = $q * $y + $r, and that the remainder (modulo) $r should
correspond to Perl's % operator as well as the bmod() method. This has
not been the actual behaviour. This patch fixes this.
- Clearer POD documentation for the bdiv() and bmod() methods.
- Changed test files to match corrected behaviour.
- Removed some duplicated tests.
---
dist/Math-BigInt/lib/Math/BigFloat.pm | 168 ++++++++++++---
dist/Math-BigInt/lib/Math/BigInt.pm | 305 +++++++++++++++++++--------
dist/Math-BigInt/lib/Math/BigInt/Calc.pm | 2 +-
dist/Math-BigInt/lib/Math/BigInt/CalcEmu.pm | 2 +-
dist/Math-BigInt/t/bare_mbf.t | 2 +-
dist/Math-BigInt/t/bare_mbi.t | 2 +-
dist/Math-BigInt/t/bigfltpm.inc | 18 +-
dist/Math-BigInt/t/bigfltpm.t | 2 +-
dist/Math-BigInt/t/bigintpm.inc | 58 +++--
dist/Math-BigInt/t/bigintpm.t | 2 +-
dist/Math-BigInt/t/inf_nan.t | 93 +++++++-
dist/Math-BigInt/t/sub_mbf.t | 2 +-
dist/Math-BigInt/t/sub_mbi.t | 2 +-
dist/Math-BigInt/t/upgrade.inc | 39 ++--
dist/Math-BigInt/t/upgrade.t | 2 +-
dist/Math-BigInt/t/with_sub.t | 2 +-
16 files changed, 495 insertions(+), 206 deletions(-)
diff --git a/dist/Math-BigInt/lib/Math/BigFloat.pm b/dist/Math-BigInt/lib/Math/BigFloat.pm
index 1c31496..209bede 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.9997';
+$VERSION = '1.999701';
require 5.006002;
require Exporter;
@@ -1776,7 +1776,7 @@ sub bmuladd
sub bdiv
{
# (dividend: BFLOAT or num_str, divisor: BFLOAT or num_str) return
- # (BFLOAT,BFLOAT) (quo,rem) or BFLOAT (only rem)
+ # (BFLOAT, BFLOAT) (quo, rem) or BFLOAT (only quo)
# set up parameters
my ($self,$x,$y,$a,$p,$r) = (ref($_[0]),@_);
@@ -1788,10 +1788,80 @@ sub bdiv
return $x if $x->modify('bdiv');
- return $self->_div_inf($x,$y)
- if (($x->{sign} !~ /^[+-]$/) || ($y->{sign} !~ /^[+-]$/) || $y->is_zero());
+ my $wantarray = wantarray; # call only once
- # x== 0 # also: or y == 1 or y == -1
+ # At least one argument is NaN. This is handled the same way as in
+ # Math::BigInt -> bdiv().
+
+ if ($x -> is_nan() || $y -> is_nan()) {
+ return $wantarray ? ($x -> bnan(), $self -> bnan()) : $x -> bnan();
+ }
+
+ # Divide by zero and modulo zero. This is handled the same way as in
+ # Math::BigInt -> bdiv(). See the comment in the code for Math::BigInt ->
+ # bdiv() for further details.
+
+ if ($y -> is_zero()) {
+ my ($quo, $rem);
+ if ($wantarray) {
+ $rem = $x -> copy();
+ }
+ if ($x -> is_zero()) {
+ $quo = $x -> bnan();
+ } else {
+ $quo = $x -> binf($x -> {sign});
+ }
+ return $wantarray ? ($quo, $rem) : $quo;
+ }
+
+ # Numerator (dividend) is +/-inf. This is handled the same way as in
+ # Math::BigInt -> bdiv(). See the comment in the code for Math::BigInt ->
+ # bdiv() for further details.
+
+ if ($x -> is_inf()) {
+ my ($quo, $rem);
+ $rem = $self -> bnan() if $wantarray;
+ if ($y -> is_inf()) {
+ $quo = $x -> bnan();
+ } else {
+ my $sign = $x -> bcmp(0) == $y -> bcmp(0) ? '+' : '-';
+ $quo = $x -> binf($sign);
+ }
+ return $wantarray ? ($quo, $rem) : $quo;
+ }
+
+ # Denominator (divisor) is +/-inf. This is handled the same way as in
+ # Math::BigInt -> bdiv(), with one exception: In scalar context,
+ # Math::BigFloat does true division (although rounded), not floored division
+ # (F-division), so a finite number divided by +/-inf is always zero. See the
+ # comment in the code for Math::BigInt -> bdiv() for further details.
+
+ if ($y -> is_inf()) {
+ my ($quo, $rem);
+ if ($wantarray) {
+ if ($x -> is_zero() || $x -> bcmp(0) == $y -> bcmp(0)) {
+ $rem = $x -> copy();
+ $quo = $x -> bzero();
+ } else {
+ $rem = $self -> binf($y -> {sign});
+ $quo = $x -> bone('-');
+ }
+ return ($quo, $rem);
+ } else {
+ if ($y -> is_inf()) {
+ if ($x -> is_nan() || $x -> is_inf()) {
+ return $x -> bnan();
+ } else {
+ return $x -> bzero();
+ }
+ }
+ }
+ }
+
+ # At this point, both the numerator and denominator are finite numbers, and
+ # the denominator (divisor) is non-zero.
+
+ # x == 0?
return wantarray ? ($x,$self->bzero()) : $x if $x->is_zero();
# upgrade ?
@@ -1805,33 +1875,30 @@ sub bdiv
return $x if $x->is_nan(); # error in _find_round_parameters?
# no rounding at all, so must use fallback
- if (scalar @params == 0)
+ if (scalar @params == 0)
{
# simulate old behaviour
$params[0] = $self->div_scale(); # and round to it as accuracy
$scale = $params[0]+4; # at least four more for proper round
$params[2] = $r; # round mode by caller or undef
$fallback = 1; # to clear a/p afterwards
- }
- else
- {
+ } else {
# the 4 below is empirical, and there might be cases where it is not
# enough...
$scale = abs($params[0] || $params[1]) + 4; # take whatever is defined
}
- my $rem; $rem = $self->bzero() if wantarray;
+ my $rem;
+ $rem = $self -> bzero() if wantarray;
$y = $self->new($y) unless $y->isa('Math::BigFloat');
- my $lx = $MBI->_len($x->{_m}); my $ly = $MBI->_len($y->{_m});
+ my $lx = $MBI -> _len($x->{_m}); my $ly = $MBI -> _len($y->{_m});
$scale = $lx if $lx > $scale;
$scale = $ly if $ly > $scale;
my $diff = $ly - $lx;
$scale += $diff if $diff > 0; # if lx << ly, but not if ly << lx!
- # already handled inf/NaN/-inf above:
-
# check that $y is not 1 nor -1 and cache the result:
my $y_not_one = !($MBI->_is_zero($y->{_e}) && $MBI->_is_one($y->{_m}));
@@ -1899,7 +1966,7 @@ sub bdiv
{
if ($y_not_one)
{
- $x -> bint();
+ $x -> bfloor();
$rem->bmod($y,@params); # copy already done
}
if ($fallback)
@@ -1926,34 +1993,54 @@ sub bmod
return $x if $x->modify('bmod');
- # handle NaN, inf, -inf
- if (($x->{sign} !~ /^[+-]$/) || ($y->{sign} !~ /^[+-]$/))
- {
- my ($d,$re) = $self->SUPER::_div_inf($x,$y);
- $x->{sign} = $re->{sign};
- $x->{_e} = $re->{_e};
- $x->{_m} = $re->{_m};
- return $x->round($a,$p,$r,$y);
+ # At least one argument is NaN. This is handled the same way as in
+ # Math::BigInt -> bmod().
+
+ if ($x -> is_nan() || $y -> is_nan()) {
+ return $x -> bnan();
}
- if ($y->is_zero())
- {
- return $x->bnan() if $x->is_zero();
+
+ # Modulo zero. This is handled the same way as in Math::BigInt -> bmod().
+
+ if ($y -> is_zero()) {
return $x;
}
+ # Numerator (dividend) is +/-inf. This is handled the same way as in
+ # Math::BigInt -> bmod().
+
+ if ($x -> is_inf()) {
+ return $x -> bnan();
+ }
+
+ # Denominator (divisor) is +/-inf. This is handled the same way as in
+ # Math::BigInt -> bmod().
+
+ if ($y -> is_inf()) {
+ if ($x -> is_zero() || $x -> bcmp(0) == $y -> bcmp(0)) {
+ return $x;
+ } else {
+ return $x -> binf($y -> sign());
+ }
+ }
+
return $x->bzero() if $x->is_zero()
|| ($x->is_int() &&
# check that $y == +1 or $y == -1:
($MBI->_is_zero($y->{_e}) && $MBI->_is_one($y->{_m})));
my $cmp = $x->bacmp($y); # equal or $x < $y?
- return $x->bzero($a,$p) if $cmp == 0; # $x == $y => result 0
+ if ($cmp == 0) { # $x == $y => result 0
+ return $x -> bzero($a, $p);
+ }
# only $y of the operands negative?
- my $neg = 0; $neg = 1 if $x->{sign} ne $y->{sign};
+ my $neg = $x->{sign} ne $y->{sign} ? 1 : 0;
$x->{sign} = $y->{sign}; # calc sign first
- return $x->round($a,$p,$r) if $cmp < 0 && $neg == 0; # $x < $y => result $x
+ if ($cmp < 0 && $neg == 0) { # $x < $y => result $x
+ return $x -> round($a, $p, $r);
+ }
my $ym = $MBI->_copy($y->{_m});
@@ -1996,7 +2083,7 @@ sub bmod
$x->{sign} = '+' if $MBI->_is_zero($x->{_m}); # fix sign for -0
$x->bnorm();
- if ($neg != 0) # one of them negative => correct in place
+ if ($neg != 0 && ! $x -> is_zero()) # one of them negative => correct in place
{
my $r = $y - $x;
$x->{_m} = $r->{_m};
@@ -4027,8 +4114,8 @@ Actual math is done by using the class defined with C<< with => Class; >>
(which defaults to BigInts) to represent the mantissa and exponent.
The sign C</^[+-]$/> is stored separately. The string 'NaN' is used to
-represent the result when input arguments are not numbers, as well as
-the result of dividing by zero.
+represent the result when input arguments are not numbers, and 'inf' and
+'-inf' are used to represent positive and negative infinity, respectively.
=head2 mantissa(), exponent() and parts()
@@ -4208,6 +4295,25 @@ Note: You probably want to use L</accuracy()> instead. With L</accuracy()> you
set the number of digits each result should have, with L</precision()> you
set the place where to round!
+=item bdiv()
+
+ $q = $x->bdiv($y);
+ ($q, $r) = $x->bdiv($y);
+
+In scalar context, divides $x by $y and returns the result to the given or
+default accuracy/precision. In list context, does floored division
+(F-division), returning an integer $q and a remainder $r so that $x = $q * $y +
+$r. The remainer (modulo) is equal to what is returned by C<$x->bmod($y)>.
+
+=item bmod()
+
+ $x->bmod($y);
+
+Returns $x modulo $y. When $x is finite, and $y is finite and non-zero, the
+result is identical to the remainder after floored division (F-division). If,
+in addition, both $x and $y are integers, the result is identical to the result
+from Perl's % operator.
+
=item bexp()
$x->bexp($accuracy); # calculate e ** X
diff --git a/dist/Math-BigInt/lib/Math/BigInt.pm b/dist/Math-BigInt/lib/Math/BigInt.pm
index 62f1be9..2381c26 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.9997';
+$VERSION = '1.999701';
@ISA = qw(Exporter);
@EXPORT_OK = qw(objectify bgcd blcm);
@@ -1657,103 +1657,175 @@ sub bmuladd
$x->round(@r);
}
-sub _div_inf
+sub bdiv
{
- # helper function that handles +-inf cases for bdiv()/bmod() to reuse code
- my ($self,$x,$y) = @_;
- # NaN if x == NaN or y == NaN or x==y==0
- return wantarray ? ($x->bnan(),$self->bnan()) : $x->bnan()
- if (($x->is_nan() || $y->is_nan()) ||
- ($x->is_zero() && $y->is_zero()));
+ # This does floored division, where the quotient is floored toward negative
+ # infinity and the remainder has the same sign as the divisor.
- # +-inf / +-inf == NaN, remainder also NaN
- if (($x->{sign} =~ /^[+-]inf$/) && ($y->{sign} =~ /^[+-]inf$/))
- {
- return wantarray ? ($x->bnan(),$self->bnan()) : $x->bnan();
+ # Set up parameters.
+ my ($self,$x,$y,@r) = (ref($_[0]),@_);
+
+ # objectify() is costly, so avoid it if we can.
+ if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) {
+ ($self,$x,$y,@r) = objectify(2,@_);
}
- # x / +-inf => 0, remainder x (works even if x == 0)
- if ($y->{sign} =~ /^[+-]inf$/)
- {
- my $t = $x->copy(); # bzero clobbers up $x
- return wantarray ? ($x->bzero(),$t) : $x->bzero()
+
+ return $x if $x->modify('bdiv');
+
+ my $wantarray = wantarray; # call only once
+
+ # At least one argument is NaN. Return NaN for both quotient and the
+ # modulo/remainder.
+
+ if ($x -> is_nan() || $y -> is_nan()) {
+ return $wantarray ? ($x -> bnan(), $self -> bnan()) : $x -> bnan();
}
- # 5 / 0 => +inf, -6 / 0 => -inf
- # +inf / 0 = inf, inf, and -inf / 0 => -inf, -inf
- # exception: -8 / 0 has remainder -8, not 8
- # exception: -inf / 0 has remainder -inf, not inf
- if ($y->is_zero())
- {
- # +-inf / 0 => special case for -inf
- return wantarray ? ($x,$x->copy()) : $x if $x->is_inf();
- if (!$x->is_zero() && !$x->is_inf())
- {
- my $t = $x->copy(); # binf clobbers up $x
- return wantarray ?
- ($x->binf($x->{sign}),$t) : $x->binf($x->{sign})
+ # Divide by zero and modulo zero.
+ #
+ # Division: Use the common convention that x / 0 is inf with the same sign
+ # as x, except when x = 0, where we return NaN. This is also what earlier
+ # versions did.
+ #
+ # Modulo: In modular arithmetic, the congruence relation z = x (mod y)
+ # means that there is some integer k such that z - x = k y. If y = 0, we
+ # get z - x = 0 or z = x. This is also what earlier versions did, except
+ # that 0 % 0 returned NaN.
+ #
+ # inf / 0 = inf inf % 0 = inf
+ # 5 / 0 = inf 5 % 0 = 5
+ # 0 / 0 = NaN 0 % 0 = 0 (before: NaN)
+ # -5 / 0 = -inf -5 % 0 = -5
+ # -inf / 0 = -inf -inf % 0 = -inf
+
+ if ($y -> is_zero()) {
+ my ($quo, $rem);
+ if ($wantarray) {
+ $rem = $x -> copy();
+ }
+ if ($x -> is_zero()) {
+ $quo = $x -> bnan();
+ } else {
+ $quo = $x -> binf($x -> {sign});
+ }
+ return $wantarray ? ($quo, $rem) : $quo;
+ }
+
+ # Numerator (dividend) is +/-inf, and denominator is finite and non-zero.
+ # The divide by zero cases are covered above. In all of the cases listed
+ # below we return the same as core Perl.
+ #
+ # inf / -inf = NaN inf % -inf = NaN
+ # inf / -5 = -inf inf % -5 = NaN (before: 0)
+ # inf / 5 = inf inf % 5 = NaN (before: 0)
+ # inf / inf = NaN inf % inf = NaN
+ #
+ # -inf / -inf = NaN -inf % -inf = NaN
+ # -inf / -5 = inf -inf % -5 = NaN (before: 0)
+ # -inf / 5 = -inf -inf % 5 = NaN (before: 0)
+ # -inf / inf = NaN -inf % inf = NaN
+
+ if ($x -> is_inf()) {
+ my ($quo, $rem);
+ $rem = $self -> bnan() if $wantarray;
+ if ($y -> is_inf()) {
+ $quo = $x -> bnan();
+ } else {
+ my $sign = $x -> bcmp(0) == $y -> bcmp(0) ? '+' : '-';
+ $quo = $x -> binf($sign);
}
+ return $wantarray ? ($quo, $rem) : $quo;
}
- # last case: +-inf / ordinary number
- my $sign = '+inf';
- $sign = '-inf' if substr($x->{sign},0,1) ne $y->{sign};
- $x->{sign} = $sign;
- return wantarray ? ($x,$self->bzero()) : $x;
+ # Denominator (divisor) is +/-inf. The cases when the numerator is +/-inf
+ # are covered above. In the modulo cases (in the right column) we return
+ # the same as core Perl, which does floored division, so for consistency we
+ # also do floored division in the division cases (in the left column).
+ #
+ # -5 / inf = -1 (before: 0) -5 % inf = inf (before: -5)
+ # 0 / inf = 0 0 % inf = 0
+ # 5 / inf = 0 5 % inf = 5
+ #
+ # -5 / -inf = 0 -5 % -inf = -5
+ # 0 / -inf = 0 0 % -inf = 0
+ # 5 / -inf = -1 (before: 0) 5 % -inf = -inf (before: 5)
+
+ if ($y -> is_inf()) {
+ my ($quo, $rem);
+ if ($x -> is_zero() || $x -> bcmp(0) == $y -> bcmp(0)) {
+ $rem = $x -> copy() if $wantarray;
+ $quo = $x -> bzero();
+ } else {
+ $rem = $self -> binf($y -> {sign}) if $wantarray;
+ $quo = $x -> bone('-');
+ }
+ return $wantarray ? ($quo, $rem) : $quo;
}
-sub bdiv
- {
- # (dividend: BINT or num_str, divisor: BINT or num_str) return
- # (BINT,BINT) (quo,rem) or BINT (only rem)
-
- # set up parameters
- my ($self,$x,$y,@r) = (ref($_[0]),@_);
- # objectify is costly, so avoid it
- if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
- {
- ($self,$x,$y,@r) = objectify(2,@_);
- }
-
- return $x if $x->modify('bdiv');
-
- return $self->_div_inf($x,$y)
- if (($x->{sign} !~ /^[+-]$/) || ($y->{sign} !~ /^[+-]$/) || $y->is_zero());
+ # At this point, both the numerator and denominator are finite numbers, and
+ # the denominator (divisor) is non-zero.
return $upgrade->bdiv($upgrade->new($x),$upgrade->new($y),@r)
if defined $upgrade;
$r[3] = $y; # no push!
- # calc new sign and in case $y == +/- 1, return $x
- my $xsign = $x->{sign}; # keep
- $x->{sign} = ($x->{sign} ne $y->{sign} ? '-' : '+');
+ # Inialize remainder.
- if (wantarray)
- {
my $rem = $self->bzero();
+
+ # Are both operands the same object, i.e., like $x -> bdiv($x)?
+ # If so, flipping the sign of $y also flips the sign of $x.
+
+ my $xsign = $x->{sign};
+ my $ysign = $y->{sign};
+
+ $y->{sign} =~ tr/+-/-+/; # Flip the sign of $y, and see ...
+ my $same = $xsign ne $x->{sign}; # ... if that changed the sign of $x.
+ $y->{sign} = $ysign; # Re-insert the original sign.
+
+ if ($same) {
+ $x -> bone();
+ } else {
($x->{value},$rem->{value}) = $CALC->_div($x->{value},$y->{value});
- $x->{sign} = '+' if $CALC->_is_zero($x->{value});
- $rem->{_a} = $x->{_a};
- $rem->{_p} = $x->{_p};
+
+ if ($CALC -> _is_zero($rem->{value})) {
+ if ($xsign eq $ysign || $CALC -> _is_zero($x->{value})) {
+ $x->{sign} = '+';
+ } else {
+ $x->{sign} = '-';
+ }
+ } else {
+ if ($xsign eq $ysign) {
+ $x->{sign} = '+';
+ } else {
+ if ($xsign eq '+') {
+ $x -> badd(1);
+ } else {
+ $x -> bsub(1);
+ }
+ $x->{sign} = '-';
+ }
+ }
+ }
+
$x->round(@r);
- if (! $CALC->_is_zero($rem->{value}))
- {
- $rem->{sign} = $y->{sign};
- $rem = $y->copy()->bsub($rem) if $xsign ne $y->{sign}; # one of them '-'
+
+ if ($wantarray) {
+ unless ($CALC -> _is_zero($rem->{value})) {
+ if ($xsign ne $ysign) {
+ $rem = $y -> copy() -> babs() -> bsub($rem);
}
- else
- {
- $rem->{sign} = '+'; # do not leave -0
+ $rem->{sign} = $ysign;
}
+ $rem->{_a} = $x->{_a};
+ $rem->{_p} = $x->{_p};
$rem->round(@r);
return ($x,$rem);
}
- $x->{value} = $CALC->_div($x->{value},$y->{value});
- $x->{sign} = '+' if $CALC->_is_zero($x->{value});
-
- $x->round(@r);
+ return $x;
}
###############################################################################
@@ -1761,11 +1833,14 @@ sub bdiv
sub bmod
{
- # modulus (or remainder)
- # (BINT or num_str, BINT or num_str) return BINT
- # set up parameters
+ # This is the remainder after floored division, where the quotient is
+ # floored toward negative infinity and the remainder has the same sign as
+ # the divisor.
+
+ # Set up parameters.
my ($self,$x,$y,@r) = (ref($_[0]),@_);
+
# objectify is costly, so avoid it
if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
{
@@ -1774,35 +1849,62 @@ sub bmod
return $x if $x->modify('bmod');
$r[3] = $y; # no push!
- if (($x->{sign} !~ /^[+-]$/) || ($y->{sign} !~ /^[+-]$/) || $y->is_zero())
- {
- my ($d,$r) = $self->_div_inf($x,$y);
- $x->{sign} = $r->{sign};
- $x->{value} = $r->{value};
- return $x->round(@r);
+
+ # At least one argument is NaN.
+
+ if ($x -> is_nan() || $y -> is_nan()) {
+ return $x -> bnan();
+ }
+
+ # Modulo zero. See documentation for bdiv().
+
+ if ($y -> is_zero()) {
+ return $x;
+ }
+
+ # Numerator (dividend) is +/-inf.
+
+ if ($x -> is_inf()) {
+ return $x -> bnan();
}
- # calc new sign and in case $y == +/- 1, return $x
+ # Denominator (divisor) is +/-inf.
+
+ if ($y -> is_inf()) {
+ if ($x -> is_zero() || $x -> bcmp(0) == $y -> bcmp(0)) {
+ return $x;
+ } else {
+ return $x -> binf($y -> sign());
+ }
+ }
+
+ # Calc new sign and in case $y == +/- 1, return $x.
+
$x->{value} = $CALC->_mod($x->{value},$y->{value});
- if (!$CALC->_is_zero($x->{value}))
+ if ($CALC -> _is_zero($x->{value}))
+ {
+ $x->{sign} = '+'; # do not leave -0
+ }
+ else
{
$x->{value} = $CALC->_sub($y->{value},$x->{value},1) # $y-$x
if ($x->{sign} ne $y->{sign});
$x->{sign} = $y->{sign};
}
- else
- {
- $x->{sign} = '+'; # do not leave -0
- }
+
$x->round(@r);
}
sub bmodinv
{
- # Return modular multiplicative inverse: z is the modular inverse of x (mod
- # y) if and only if x*z (mod y) = 1 (mod y). If the modulus y is larger than
- # one, x and z are relative primes (i.e., their greatest common divisor is
- # one).
+ # Return modular multiplicative inverse:
+ #
+ # z is the modular inverse of x (mod y) if and only if
+ #
+ # x*z ≡ 1 (mod y)
+ #
+ # If the modulus y is larger than one, x and z are relative primes (i.e.,
+ # their greatest common divisor is one).
#
# If no modular multiplicative inverse exists, NaN is returned.
@@ -1896,8 +1998,17 @@ sub bmodpow
return $num->bnan() if ($num->{sign} =~ /NaN|inf/ || # NaN, -inf, +inf
$exp->{sign} =~ /NaN|inf/ || # NaN, -inf, +inf
- $mod->{sign} =~ /NaN|inf/ || # NaN, -inf, +inf
- $mod->is_zero());
+ $mod->{sign} =~ /NaN|inf/); # NaN, -inf, +inf
+
+ # Modulo zero. See documentation for Math::BigInt's bmod() method.
+
+ if ($mod -> is_zero()) {
+ if ($num -> is_zero()) {
+ return $self -> bnan();
+ } else {
+ return $num -> copy();
+ }
+ }
# Compute 'a (mod m)', ignoring the signs on 'a' and 'm'. If the resulting
# value is zero, the output is also zero, regardless of the signs on 'a' and
@@ -3927,12 +4038,20 @@ This method was added in v1.87 of Math::BigInt (June 2007).
=item bdiv()
$x->bdiv($y); # divide, set $x to quotient
- # return (quo,rem) or quo if scalar
+
+Returns $x divided by $y. In list context, does floored division (F-division),
+where the quotient is the greatest integer less than or equal to the quotient
+of the two operands. Consequently, the remainder is either zero or has the same
+sign as the second operand. In scalar context, only the quotient is returned.
=item bmod()
$x->bmod($y); # modulus (x % y)
+Returns $x modulo $y. When $x is finite, and $y is finite and non-zero, the
+result is identical to the remainder after floored division (F-division), i.e.,
+identical to the result from Perl's % operator.
+
=item bmodinv()
$x->bmodinv($mod); # modular multiplicative inverse
diff --git a/dist/Math-BigInt/lib/Math/BigInt/Calc.pm b/dist/Math-BigInt/lib/Math/BigInt/Calc.pm
index d511bab..ce9bf3a 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; # do not use warnings for older Perls
-our $VERSION = '1.9997';
+our $VERSION = '1.999701';
# Package to store unsigned big integers in decimal and do math with them
diff --git a/dist/Math-BigInt/lib/Math/BigInt/CalcEmu.pm b/dist/Math-BigInt/lib/Math/BigInt/CalcEmu.pm
index 9bf3e07..0ff9dcc 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; # do not use warnings for older Perls
use vars qw/$VERSION/;
-$VERSION = '1.9997';
+$VERSION = '1.999701';
package Math::BigInt;
diff --git a/dist/Math-BigInt/t/bare_mbf.t b/dist/Math-BigInt/t/bare_mbf.t
index 49ba8cb..8f37270 100644
--- a/dist/Math-BigInt/t/bare_mbf.t
+++ b/dist/Math-BigInt/t/bare_mbf.t
@@ -1,7 +1,7 @@
#!/usr/bin/perl -w
use strict;
-use Test::More tests => 2338;
+use Test::More tests => 2336;
BEGIN { unshift @INC, 't'; }
diff --git a/dist/Math-BigInt/t/bare_mbi.t b/dist/Math-BigInt/t/bare_mbi.t
index eaedbf7..8aedf43 100644
--- a/dist/Math-BigInt/t/bare_mbi.t
+++ b/dist/Math-BigInt/t/bare_mbi.t
@@ -1,7 +1,7 @@
#!/usr/bin/perl -w
use strict;
-use Test::More tests => 3651;
+use Test::More tests => 3649;
BEGIN { unshift @INC, 't'; }
diff --git a/dist/Math-BigInt/t/bigfltpm.inc b/dist/Math-BigInt/t/bigfltpm.inc
index 1528e48..2ffeafa 100644
--- a/dist/Math-BigInt/t/bigfltpm.inc
+++ b/dist/Math-BigInt/t/bigfltpm.inc
@@ -1404,7 +1404,7 @@ NaNmul:-inf:NaN
6:120:720
10:10000:100000
&fdiv-list
-0:0:NaN,NaN
+0:0:NaN,0
0:1:0,0
9:4:2,1
9:5:1,4
@@ -1499,13 +1499,13 @@ $div_scale = 40
0:inf:0
0:-inf:0
5:inf:5
-5:-inf:5
--5:inf:-5
+5:-inf:-inf
+-5:inf:inf
-5:-inf:-5
-inf:5:0
--inf:5:0
-inf:-5:0
--inf:-5:0
+inf:5:NaN
+-inf:5:NaN
+inf:-5:NaN
+-inf:-5:NaN
5:5:0
-5:-5:0
inf:inf:NaN
@@ -1514,14 +1514,12 @@ inf:inf:NaN
inf:-inf:NaN
8:0:8
inf:0:inf
-# exceptions to remainder rule
-inf:0:-inf
-8:0:-8
-0:0:NaN
+0:0:0
abc:abc:NaN
abc:1:abc:NaN
1:abc:NaN
-0:0:NaN
0:1:0
1:0:1
0:-1:0
diff --git a/dist/Math-BigInt/t/bigfltpm.t b/dist/Math-BigInt/t/bigfltpm.t
index de3c80e..6f6e598 100644
--- a/dist/Math-BigInt/t/bigfltpm.t
+++ b/dist/Math-BigInt/t/bigfltpm.t
@@ -1,7 +1,7 @@
#!/usr/bin/perl -w
use strict;
-use Test::More tests => 2338
+use Test::More tests => 2336
+ 5; # own tests
diff --git a/dist/Math-BigInt/t/bigintpm.inc b/dist/Math-BigInt/t/bigintpm.inc
index c3e815c..1481502 100644
--- a/dist/Math-BigInt/t/bigintpm.inc
+++ b/dist/Math-BigInt/t/bigintpm.inc
@@ -1548,19 +1548,19 @@ NaNmul:-inf:NaN
5:8:0,5
0:8:0,0
11:2:5,1
-11:-2:-5,-1
--11:2:-5,1
+11:-2:-6,-1
+-11:2:-6,1
# see table in documentation in MBI
0:inf:0,0
0:-inf:0,0
5:inf:0,5
-5:-inf:0,5
--5:inf:0,-5
+5:-inf:-1,-inf
+-5:inf:-1,inf
-5:-inf:0,-5
-inf:5:inf,0
--inf:5:-inf,0
-inf:-5:-inf,0
--inf:-5:inf,0
+inf:5:inf,NaN
+-inf:5:-inf,NaN
+inf:-5:-inf,NaN
+-inf:-5:inf,NaN
5:5:1,0
-5:-5:1,0
inf:inf:NaN,NaN
@@ -1572,7 +1572,7 @@ inf:0:inf,inf
# exceptions to remainder rule
-8:0:-inf,-8
-inf:0:-inf,-inf
-0:0:NaN,NaN
+0:0:NaN,0
# test the shortcut in Calc if @$x == @$yorg
1234567812345678:123456712345678:10,688888898
12345671234567:1234561234567:10,58888897
@@ -1615,8 +1615,8 @@ abc:1:NaN
0:inf:0
0:-inf:0
5:inf:0
-5:-inf:0
--5:inf:0
+5:-inf:-1
+-5:inf:-1
-5:-inf:0
inf:5:inf
-inf:5:-inf
@@ -1635,8 +1635,8 @@ inf:0:inf
0:0:NaN
11:2:5
-11:-2:5
--11:2:-5
-11:-2:-5
+-11:2:-6
+11:-2:-6
0:1:0
0:-1:0
1:1:1
@@ -1670,17 +1670,17 @@ inf:0:inf
999999999999999:99999:10000100001
+1111088889:99999:11111
-5:-3:1
--5:3:-1
+-5:3:-2
4:3:1
-4:-3:-1
+4:-3:-2
1:3:0
-1:-3:0
+1:-3:-1
-2:-3:0
--2:3:0
+-2:3:-1
8:3:2
--8:3:-2
-14:-3:-4
--14:3:-4
+-8:3:-3
+14:-3:-5
+-14:3:-5
-14:-3:4
14:3:4
# bug in Calc with '99999' vs $BASE-1
@@ -1774,7 +1774,7 @@ abc:abc:5:NaN
5:5:abc:NaN
5:abc:5:NaN
abc:5:5:NaN
-3:5:0:NaN
+3:5:0:3
# bmodpow Expected results
0:0:2:1
1:0:2:1
@@ -1940,13 +1940,13 @@ inf:5:13:NaN
0:inf:0
0:-inf:0
5:inf:5
-5:-inf:5
--5:inf:-5
+5:-inf:-inf
+-5:inf:inf
-5:-inf:-5
-inf:5:0
--inf:5:0
-inf:-5:0
--inf:-5:0
+inf:5:NaN
+-inf:5:NaN
+inf:-5:NaN
+-inf:-5:NaN
5:5:0
-5:-5:0
inf:inf:NaN
@@ -1955,14 +1955,12 @@ inf:inf:NaN
inf:-inf:NaN
8:0:8
inf:0:inf
-# exceptions to remainder rule
-inf:0:-inf
-8:0:-8
-0:0:NaN
+0:0:0
abc:abc:NaN
abc:1:abc:NaN
1:abc:NaN
-0:0:NaN
0:1:0
1:0:1
0:-1:0
diff --git a/dist/Math-BigInt/t/bigintpm.t b/dist/Math-BigInt/t/bigintpm.t
index 8f009ec..a03710e 100644
--- a/dist/Math-BigInt/t/bigintpm.t
+++ b/dist/Math-BigInt/t/bigintpm.t
@@ -1,7 +1,7 @@
#!/usr/bin/perl -w
use strict;
-use Test::More tests => 3651 + 6;
+use Test::More tests => 3649 + 6;
use Math::BigInt lib => 'Calc';
diff --git a/dist/Math-BigInt/t/inf_nan.t b/dist/Math-BigInt/t/inf_nan.t
index b3f61ba..270689b 100644
--- a/dist/Math-BigInt/t/inf_nan.t
+++ b/dist/Math-BigInt/t/inf_nan.t
@@ -18,10 +18,10 @@ use Math::BigFloat;
use Math::BigInt::Subclass;
use Math::BigFloat::Subclass;
-my @classes =
- qw/Math::BigInt Math::BigFloat
- Math::BigInt::Subclass Math::BigFloat::Subclass
- /;
+my @biclasses =
+ qw/ Math::BigInt Math::BigInt::Subclass /;
+my @bfclasses =
+ qw/ Math::BigFloat Math::BigFloat::Subclass /;
my (@args,$x,$y,$z);
@@ -77,7 +77,7 @@ foreach (qw/
/)
{
@args = split /:/,$_;
- for my $class (@classes)
+ for my $class (@biclasses, @bfclasses)
{
$x = $class->new($args[0]);
$y = $class->new($args[1]);
@@ -141,7 +141,7 @@ foreach (qw/
/)
{
@args = split /:/,$_;
- for my $class (@classes)
+ for my $class (@biclasses, @bfclasses)
{
$x = $class->new($args[0]);
$y = $class->new($args[1]);
@@ -205,7 +205,7 @@ foreach (qw/
/)
{
@args = split /:/,$_;
- for my $class (@classes)
+ for my $class (@biclasses, @bfclasses)
{
$x = $class->new($args[0]);
$y = $class->new($args[1]);
@@ -224,7 +224,7 @@ foreach (qw/
-1:-inf:0
-0:-inf:0
0:-inf:-0
- 1:-inf:-0
+ 1:-inf:-1
inf:-inf:NaN
NaN:-inf:NaN
@@ -253,7 +253,7 @@ foreach (qw/
NaN:1:NaN
-inf:inf:NaN
- -1:inf:-0
+ -1:inf:-1
-0:inf:-0
0:inf:0
1:inf:0
@@ -270,7 +270,7 @@ foreach (qw/
/)
{
@args = split /:/,$_;
- for my $class (@classes)
+ for my $class (@biclasses, @bfclasses)
{
$x = $class->new($args[0]);
$y = $class->new($args[1]);
@@ -280,9 +280,11 @@ foreach (qw/
my $tmod = $t->copy();
# bdiv in scalar context
+ unless ($class =~ /^Math::BigFloat/) {
my $r = $x->bdiv($y);
is($x->bstr(),$args[2],"x $class $args[0] / $args[1]");
is($r->bstr(),$args[2],"r $class $args[0] / $args[1]");
+ }
# bmod and bdiv in list context
my ($d,$rem) = $t->bdiv($y);
@@ -302,6 +304,75 @@ foreach (qw/
}
}
+# /
+foreach (qw/
+ -inf:-inf:NaN
+ -1:-inf:0
+ -0:-inf:0
+ 0:-inf:-0
+ 1:-inf:-0
+ inf:-inf:NaN
+ NaN:-inf:NaN
+
+ -inf:-1:inf
+ -1:-1:1
+ -0:-1:0
+ 0:-1:-0
+ 1:-1:-1
+ inf:-1:-inf
+ NaN:-1:NaN
+
+ -inf:0:-inf
+ -1:0:-inf
+ -0:0:NaN
+ 0:0:NaN
+ 1:0:inf
+ inf:0:inf
+ NaN:0:NaN
+
+ -inf:1:-inf
+ -1:1:-1
+ -0:1:-0
+ 0:1:0
+ 1:1:1
+ inf:1:inf
+ NaN:1:NaN
+
+ -inf:inf:NaN
+ -1:inf:-0
+ -0:inf:-0
+ 0:inf:0
+ 1:inf:0
+ inf:inf:NaN
+ NaN:inf:NaN
+
+ -inf:NaN:NaN
+ -1:NaN:NaN
+ -0:NaN:NaN
+ 0:NaN:NaN
+ 1:NaN:NaN
+ inf:NaN:NaN
+ NaN:NaN:NaN
+ /)
+ {
+ @args = split /:/,$_;
+ for my $class (@bfclasses)
+ {
+ $x = $class->new($args[0]);
+ $y = $class->new($args[1]);
+ $args[2] = '0' if $args[2] eq '-0'; # BigInt/Float hasn't got -0
+
+ my $t = $x->copy();
+ my $tmod = $t->copy();
+
+ # bdiv in scalar context
+ my $r = $x->bdiv($y);
+ is($x->bstr(),$args[2],"x $class $args[0] / $args[1]");
+ is($r->bstr(),$args[2],"r $class $args[0] / $args[1]");
+
+ }
+ }
+
#############################################################################
# overloaded comparisons
@@ -309,7 +380,7 @@ foreach (qw/
# mind what NaN actually is, see [perl #33106].
#
-#foreach my $c (@classes)
+#foreach my $c (@biclasses, @bfclasses)
# {
# my $x = $c->bnan();
# my $y = $c->bnan(); # test with two different objects, too
diff --git a/dist/Math-BigInt/t/sub_mbf.t b/dist/Math-BigInt/t/sub_mbf.t
index 061b06a..28252b4 100644
--- a/dist/Math-BigInt/t/sub_mbf.t
+++ b/dist/Math-BigInt/t/sub_mbf.t
@@ -1,7 +1,7 @@
#!/usr/bin/perl -w
use strict;
-use Test::More tests => 2338
+use Test::More tests => 2336
+ 6; # + our own tests
diff --git a/dist/Math-BigInt/t/sub_mbi.t b/dist/Math-BigInt/t/sub_mbi.t
index e23389d..b8e0a02 100644
--- a/dist/Math-BigInt/t/sub_mbi.t
+++ b/dist/Math-BigInt/t/sub_mbi.t
@@ -1,7 +1,7 @@
#!/usr/bin/perl -w
use strict;
-use Test::More tests => 3651
+use Test::More tests => 3649
+ 5; # +5 own tests
BEGIN { unshift @INC, 't'; }
diff --git a/dist/Math-BigInt/t/upgrade.inc b/dist/Math-BigInt/t/upgrade.inc
index ef0a6ea..16ca05e 100644
--- a/dist/Math-BigInt/t/upgrade.inc
+++ b/dist/Math-BigInt/t/upgrade.inc
@@ -841,19 +841,19 @@ NaNmul:-inf:NaN
5:8:0,5
0:8:0,0
11:2:5,1
-11:-2:-5,-1
--11:2:-5,1
+11:-2:-6,-1
+-11:2:-6,1
# see table in documentation in MBI
0:inf:0,0
0:-inf:0,0
5:inf:0,5
-5:-inf:0,5
--5:inf:0,-5
+5:-inf:-1,-inf
+-5:inf:-1,inf
-5:-inf:0,-5
-inf:5:inf,0
--inf:5:-inf,0
-inf:-5:-inf,0
--inf:-5:inf,0
+inf:5:inf,NaN
+-inf:5:-inf,NaN
+inf:-5:-inf,NaN
+-inf:-5:inf,NaN
5:5:1,0
-5:-5:1,0
inf:inf:NaN,NaN
@@ -865,7 +865,7 @@ inf:0:inf,inf
# exceptions to remainder rule
-8:0:-inf,-8
-inf:0:-inf,-inf
-0:0:NaN,NaN
+0:0:NaN,0
&bdiv
abc:abc:NaN
abc:1:NaN
@@ -875,8 +875,8 @@ abc:1:NaN
0:inf:0
0:-inf:0
5:inf:0
-5:-inf:0
--5:inf:0
+5:-inf:-1
+-5:inf:-1
-5:-inf:0
inf:5:inf
-inf:5:-inf
@@ -892,7 +892,6 @@ inf:-inf:NaN
inf:0:inf
-8:0:-inf
-inf:0:-inf
-0:0:NaN
11:2:5.5^
-11:-2:5.5^
-11:2:-5.5^
@@ -950,13 +949,13 @@ inf:0:inf
0:inf:0
0:-inf:0
5:inf:5
-5:-inf:5
--5:inf:-5
+5:-inf:-inf
+-5:inf:inf
-5:-inf:-5
-inf:5:0
--inf:5:0
-inf:-5:0
--inf:-5:0
+inf:5:NaN
+-inf:5:NaN
+inf:-5:NaN
+-inf:-5:NaN
5:5:0
-5:-5:0
inf:inf:NaN
@@ -965,14 +964,12 @@ inf:inf:NaN
inf:-inf:NaN
8:0:8
inf:0:inf
-# exceptions to remainder rule
-inf:0:-inf
-8:0:-8
-0:0:NaN
+0:0:0
abc:abc:NaN
abc:1:abc:NaN
1:abc:NaN
-0:0:NaN
0:1:0
1:0:1
0:-1:0
diff --git a/dist/Math-BigInt/t/upgrade.t b/dist/Math-BigInt/t/upgrade.t
index ab09f53..d209879 100644
--- a/dist/Math-BigInt/t/upgrade.t
+++ b/dist/Math-BigInt/t/upgrade.t
@@ -1,7 +1,7 @@
#!/usr/bin/perl -w
use strict;
-use Test::More tests => 2128
+use Test::More tests => 2124
+ 2; # our own tests
use Math::BigInt upgrade => 'Math::BigFloat';
diff --git a/dist/Math-BigInt/t/with_sub.t b/dist/Math-BigInt/t/with_sub.t
index 6f5d72d..48dfa30 100644
--- a/dist/Math-BigInt/t/with_sub.t
+++ b/dist/Math-BigInt/t/with_sub.t
@@ -3,7 +3,7 @@
# Test use Math::BigFloat with => 'Math::BigInt::SomeSubclass';
use strict;
-use Test::More tests => 2338 + 1;
+use Test::More tests => 2336 + 1;
use Math::BigFloat with => 'Math::BigInt::Subclass', lib => 'Calc';
--
1.7.10.4
|
From @tonycozOn Mon Apr 27 22:30:13 2015, tonyc wrote:
Thanks, applied to blead as b4a10d3. Have you considered making the Math::Big* modules cpan upstream? Tony |
@tonycoz - Status changed from 'open' to 'resolved' |
@tonycoz - Status changed from 'resolved' to 'pending release' |
From @pjacklamThis was fixed in Math-BigInt-1.9994. |
From @khwilliamsonThank you for submitting this report. You have helped make Perl better. Perl 5.24.0 may be downloaded via https://metacpan.org/release/RJBS/perl-5.24.0 |
@khwilliamson - Status changed from 'pending release' to 'resolved' |
Migrated from rt.perl.org#124300 (status was 'resolved')
Searchable as RT124300$
The text was updated successfully, but these errors were encountered: