This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
bmodpow() fails when GMP library is used.
authorPeter John Acklam <pjacklam@online.no>
Sat, 29 Jan 2011 02:00:30 +0000 (18:00 -0800)
committerFather Chrysostomos <sprout@cpan.org>
Sat, 29 Jan 2011 04:19:51 +0000 (20:19 -0800)
This bug is not seen when the libraries Calc and FastCalc are used,
because their _modpow() method modifies the first argument. However,
the GMP library's _modpow() does not modify the first argument,
causing a so far undetected bug to show up and fail tests.

Using the Calc library prints the correct "-4":

    use Math::BigInt lib => Calc;
    $x = Math::BigInt->new(8);
    $y = Math::BigInt->new(8);
    $z = Math::BigInt->new(-5);
    print $x -> bmodpow($y, $z), "\n";

Using the GMP library prints the incorrect "--":

    use Math::BigInt lib => GMP;
    $x = Math::BigInt->new(8);
    $y = Math::BigInt->new(8);
    $z = Math::BigInt->new(-5);
    print $x -> bmodpow($y, $z), "\n";

dist/Math-BigInt/lib/Math/BigInt.pm

index 45a0f01..177894a 100644 (file)
@@ -18,7 +18,7 @@ package Math::BigInt;
 my $class = "Math::BigInt";
 use 5.006002;
 
-$VERSION = '1.99_04';
+$VERSION = '1.99_05';
 
 @ISA = qw(Exporter);
 @EXPORT_OK = qw(objectify bgcd blcm); 
@@ -1858,9 +1858,9 @@ sub bmodinv
 
 sub bmodpow
   {
-  # takes a very large number to a very large exponent in a given very
-  # large modulus, quickly, thanks to binary exponentiation. Supports
-  # negative exponents.
+  # Modular exponentiation. Raises a very large number to a very large exponent
+  # in a given very large modulus quickly, thanks to binary exponentiation.
+  # Supports negative exponents.
   my ($self,$num,$exp,$mod,@r) = objectify(3,@_);
 
   return $num if $num->modify('bmodpow');
@@ -1890,7 +1890,7 @@ sub bmodpow
   # If the resulting value is non-zero, we have four special cases, depending
   # on the signs on 'a' and 'm'.
 
-  unless ($CALC->_is_zero($num->{value})) {
+  unless ($CALC->_is_zero($value)) {
 
       # There is a negative sign on 'a' (= $num**$exp) only if the number we
       # are exponentiating ($num) is negative and the exponent ($exp) is odd.
@@ -1913,7 +1913,7 @@ sub bmodpow
           else {
               # Use copy of $mod since _sub() modifies the first argument.
               my $mod = $CALC->_copy($mod->{value});
-              $value = $CALC->_sub($mod, $num->{value});
+              $value = $CALC->_sub($mod, $value);
               $sign  = '+';
           }
 
@@ -1925,8 +1925,9 @@ sub bmodpow
           #               = -(m - (a (mod m)))
 
           if ($mod->{sign} eq '-') {
+              # Use copy of $mod since _sub() modifies the first argument.
               my $mod = $CALC->_copy($mod->{value});
-              $value = $CALC->_sub($mod, $num->{value});
+              $value = $CALC->_sub($mod, $value);
               $sign  = '-';
           }