Skip to content
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

Closed
p5pRT opened this issue Apr 14, 2015 · 14 comments
Closed

[PATCH] Correct bdiv() and bmod() in Math::BigInt and Math::BigFloat #14650

p5pRT opened this issue Apr 14, 2015 · 14 comments

Comments

@p5pRT
Copy link

p5pRT commented Apr 14, 2015

Migrated from rt.perl.org#124300 (status was 'resolved')

Searchable as RT124300$

@p5pRT
Copy link
Author

p5pRT commented Apr 14, 2015

From @pjacklam

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.

- This patch fixes CPAN RT 66633 and CPAN RT 92953.

@p5pRT
Copy link
Author

p5pRT commented Apr 14, 2015

From @pjacklam

0001-Correct-bdiv-and-bmod-in-Math-BigInt-and-Math-BigFlo.patch
From 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

@p5pRT
Copy link
Author

p5pRT commented Apr 15, 2015

From @jkeenan

On Tue Apr 14 07​:28​:11 2015, pjacklam wrote​:

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.

- This patch fixes CPAN RT 66633 and CPAN RT 92953.

Smoke-testing in branch smoke-me/jkeenan/124300-124303-Math-BigIntRat

--
James E Keenan (jkeenan@​cpan.org)

@p5pRT
Copy link
Author

p5pRT commented Apr 15, 2015

The RT System itself - Status changed from 'new' to 'open'

@p5pRT
Copy link
Author

p5pRT commented Apr 15, 2015

From @tonycoz

On Tue Apr 14 07​:28​:11 2015, pjacklam wrote​:

Correct bdiv() and bmod() in Math​::BigInt and Math​::BigFloat

From the patch header​:

From 494435bf42409d6e166d8cbe9555a8df90b19c2c Mon Sep 17 00​:00​:00 2001
From​: pjacklam <pjacklam@​gmail.com>
Date​: Tue, 14 Apr 2015 15​:20​:14 +0200

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

@p5pRT
Copy link
Author

p5pRT commented Apr 15, 2015

From @pjacklam

Yes, 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>​:

On Tue Apr 14 07​:28​:11 2015, pjacklam wrote​:

Correct bdiv() and bmod() in Math​::BigInt and Math​::BigFloat

From the patch header​:

From 494435bf42409d6e166d8cbe9555a8df90b19c2c Mon Sep 17 00​:00​:00 2001
From​: pjacklam <pjacklam@​gmail.com>
Date​: Tue, 14 Apr 2015 15​:20​:14 +0200

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

@p5pRT
Copy link
Author

p5pRT commented Apr 28, 2015

From @tonycoz

On Tue Apr 14 18​:55​:03 2015, tonyc wrote​:

The name part of the author is different too.

The same is true of the #124303 patch.

Here's the corrected patch, if anyone beats me to it after blead is re-opened.

Also in my post-5.22 branch.

Tony

@p5pRT
Copy link
Author

p5pRT commented Apr 28, 2015

From @tonycoz

0001-Correct-bdiv-and-bmod-in-Math-BigInt-and-Math-BigFlo.patch
From 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

@p5pRT
Copy link
Author

p5pRT commented Jun 2, 2015

From @tonycoz

On Mon Apr 27 22​:30​:13 2015, tonyc wrote​:

On Tue Apr 14 18​:55​:03 2015, tonyc wrote​:

The name part of the author is different too.

The same is true of the #124303 patch.

Here's the corrected patch, if anyone beats me to it after blead is
re-opened.

Also in my post-5.22 branch.

Thanks, applied to blead as b4a10d3.

Have you considered making the Math​::Big* modules cpan upstream?

Tony

@p5pRT
Copy link
Author

p5pRT commented Jun 2, 2015

@tonycoz - Status changed from 'open' to 'resolved'

@p5pRT
Copy link
Author

p5pRT commented Jun 4, 2015

@tonycoz - Status changed from 'resolved' to 'pending release'

@p5pRT
Copy link
Author

p5pRT commented Sep 15, 2015

From @pjacklam

This was fixed in Math-BigInt-1.9994.

@p5pRT
Copy link
Author

p5pRT commented May 13, 2016

From @khwilliamson

Thank you for submitting this report. You have helped make Perl better.
 
With the release of Perl 5.24.0 on May 9, 2016, this and 149 other issues have been resolved.

Perl 5.24.0 may be downloaded via https://metacpan.org/release/RJBS/perl-5.24.0

@p5pRT p5pRT closed this as completed May 13, 2016
@p5pRT
Copy link
Author

p5pRT commented May 13, 2016

@khwilliamson - Status changed from 'pending release' to 'resolved'

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant