Skip Menu |

This queue is for tickets about the Math-BigInt CPAN distribution.

Report information
The Basics
Id: 61543
Status: resolved
Priority: 0/
Queue: Math-BigInt

People
Owner: Nobody in particular
Requestors: mhasch-cpanbugs [...] cozap.com
Cc:
AdminCc:

Bug Information
Severity: Important
Broken in: 1.95
Fixed in: (no value)



Subject: [PATCH] bmodpow gives wrong results for powers of zero or negative numbers
I have added a couple of tests for bmodpow (patch #1). Apparently, this operator works only for powers of positive values. This could be fixed with an initial modulo operation (getting rid of negative values and mapping multiples of the modulus to zero) and a better coverage of the zero case. Patch #2 suggests such a solution. Someone with deeper understanding of the module internals, please validate.
Subject: check_bmodpow.patch
diff -ru Math-BigInt-1.95.orig/t/bare_mbi.t Math-BigInt-1.95/t/bare_mbi.t --- Math-BigInt-1.95.orig/t/bare_mbi.t 2010-09-13 16:28:42.000000000 +0200 +++ Math-BigInt-1.95/t/bare_mbi.t 2010-09-22 02:37:42.000000000 +0200 @@ -1,7 +1,7 @@ #!/usr/bin/perl -w use strict; -use Test::More tests => 3279; +use Test::More tests => 3304; BEGIN { unshift @INC, 't'; } diff -ru Math-BigInt-1.95.orig/t/bigintpm.inc Math-BigInt-1.95/t/bigintpm.inc --- Math-BigInt-1.95.orig/t/bigintpm.inc 2010-09-13 16:28:42.000000000 +0200 +++ Math-BigInt-1.95/t/bigintpm.inc 2010-09-22 02:35:22.000000000 +0200 @@ -664,6 +664,46 @@ $x = $class->new(-3); $x %= $x; is ($x, 0); ############################################################################### +# bmodpow + +$y = $class->new(3); + +$z = $class->new(-1); +$x = $z->copy->bmodpow(-2, $y); is ($x, 1); +$x = $z->copy->bmodpow(-1, $y); is ($x, 2); +$x = $z->copy->bmodpow( 0, $y); is ($x, 1); +$x = $z->copy->bmodpow( 1, $y); is ($x, 2); +$x = $z->copy->bmodpow( 2, $y); is ($x, 1); + +$z = $class->new(0); +$x = $z->copy->bmodpow(-2, $y); is ($x->is_nan(), 1); +$x = $z->copy->bmodpow(-1, $y); is ($x->is_nan(), 1); +$x = $z->copy->bmodpow( 0, $y); is ($x, 1); +$x = $z->copy->bmodpow( 1, $y); is ($x, 0); +$x = $z->copy->bmodpow( 2, $y); is ($x, 0); + +$z = $class->new(1); +$x = $z->copy->bmodpow(-2, $y); is ($x, 1); +$x = $z->copy->bmodpow(-1, $y); is ($x, 1); +$x = $z->copy->bmodpow( 0, $y); is ($x, 1); +$x = $z->copy->bmodpow( 1, $y); is ($x, 1); +$x = $z->copy->bmodpow( 2, $y); is ($x, 1); + +$z = $class->new(2); +$x = $z->copy->bmodpow(-2, $y); is ($x, 1); +$x = $z->copy->bmodpow(-1, $y); is ($x, 2); +$x = $z->copy->bmodpow( 0, $y); is ($x, 1); +$x = $z->copy->bmodpow( 1, $y); is ($x, 2); +$x = $z->copy->bmodpow( 2, $y); is ($x, 1); + +$z = $class->new(3); +$x = $z->copy->bmodpow(-2, $y); is ($x->is_nan(), 1); +$x = $z->copy->bmodpow(-1, $y); is ($x->is_nan(), 1); +$x = $z->copy->bmodpow( 0, $y); is ($x, 1); +$x = $z->copy->bmodpow( 1, $y); is ($x, 0); +$x = $z->copy->bmodpow( 2, $y); is ($x, 0); + +############################################################################### # all tests done 1; diff -ru Math-BigInt-1.95.orig/t/bigintpm.t Math-BigInt-1.95/t/bigintpm.t --- Math-BigInt-1.95.orig/t/bigintpm.t 2010-09-13 16:28:42.000000000 +0200 +++ Math-BigInt-1.95/t/bigintpm.t 2010-09-22 02:37:49.000000000 +0200 @@ -1,7 +1,7 @@ #!/usr/bin/perl -w use strict; -use Test::More tests => 3279 + 6; +use Test::More tests => 3304 + 6; use Math::BigInt lib => 'Calc'; diff -ru Math-BigInt-1.95.orig/t/sub_mbi.t Math-BigInt-1.95/t/sub_mbi.t --- Math-BigInt-1.95.orig/t/sub_mbi.t 2010-09-13 16:28:42.000000000 +0200 +++ Math-BigInt-1.95/t/sub_mbi.t 2010-09-22 02:38:02.000000000 +0200 @@ -1,7 +1,7 @@ #!/usr/bin/perl -w use strict; -use Test::More tests => 3279 +use Test::More tests => 3304 + 5; # +5 own tests BEGIN { unshift @INC, 't'; }
Subject: fix_bmodpow.patch
diff -ru Math-BigInt-1.95.orig/lib/Math/BigInt/Calc.pm Math-BigInt-1.95/lib/Math/BigInt/Calc.pm --- Math-BigInt-1.95.orig/lib/Math/BigInt/Calc.pm 2010-09-13 16:33:34.000000000 +0200 +++ Math-BigInt-1.95/lib/Math/BigInt/Calc.pm 2010-09-22 02:32:55.000000000 +0200 @@ -2385,10 +2385,17 @@ splice @$num,0,1; $num->[0] = 0; return $num; } - if ((scalar @$num == 1) && (($num->[0] == 0) || ($num->[0] == 1))) + if (scalar @$num == 1) { - $num->[0] = 1; - return $num; + if ($num->[0] == 1 || _is_zero($c, $exp)) + { + $num->[0] = 1; + return $num; + } + if ($num->[0] == 0) + { + return $num; + } } # $num = _mod($c,$num,$mod); # this does not make it faster diff -ru Math-BigInt-1.95.orig/lib/Math/BigInt.pm Math-BigInt-1.95/lib/Math/BigInt.pm --- Math-BigInt-1.95.orig/lib/Math/BigInt.pm 2010-09-14 00:28:40.000000000 +0200 +++ Math-BigInt-1.95/lib/Math/BigInt.pm 2010-09-22 03:11:50.000000000 +0200 @@ -1843,6 +1843,9 @@ # check num for valid values (also NaN if there was no inverse but $exp < 0) return $num->bnan() if $num->{sign} !~ /^[+-]$/; + # project num into the range 0..mod-1 + $num->bmod($mod); + # $mod is positive, sign on $exp is ignored, result also positive $num->{value} = $CALC->_modpow($num->{value},$exp->{value},$mod->{value}); $num;
Fixed in Math::BigInt version 1.991.