Skip Menu |

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

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

People
Owner: Nobody in particular
Requestors: peter.john.acklam [...] gmail.com
Cc:
AdminCc:

Bug Information
Severity: Normal
Broken in: 1.96
Fixed in: (no value)



Subject: digit($n) should return 0 for digits "out of range"
If digit($n) is given a value $n which refers to a position outside of the number, 0 should be returned. For instance, $ perl -MMath::BigInt -wle 'print Math::BigInt -> new(123) -> digit(4)' returns 1, but should return 0 (or error). Similarly, $ perl -MMath::BigInt -wle 'print Math::BigInt -> new(123) -> digit(-4)' returns 2, but should also return 0 (or error).
I have attached a patch to Math-BigInt-1.96 that fixes this bug. I have also added a test suite entry that caches this case and verifies that it works correctly.
Subject: Math-BigInt-1.96.patch
diff -ru Math-BigInt-1.96//lib/Math/BigInt/Calc.pm Math-BigInt-1.96-patched//lib/Math/BigInt/Calc.pm --- Math-BigInt-1.96//lib/Math/BigInt/Calc.pm 2010-09-28 06:34:18.000000000 +0200 +++ Math-BigInt-1.96-patched//lib/Math/BigInt/Calc.pm 2010-10-01 14:21:29.946547200 +0200 @@ -1206,20 +1206,18 @@ sub _digit { - # return the nth digit, negative values count backward - # zero is rightmost, so _digit(123,0) will give 3 - my ($c,$x,$n) = @_; + # Return the nth digit. Zero is rightmost, so _digit(123,0) gives 3. + # Negative values count from the left, so _digit(123, -1) gives 1. + my ($class, $x, $n) = @_; - my $len = _len('',$x); + my $len = _len('', $x); - $n = $len+$n if $n < 0; # -1 last, -2 second-to-last - $n = abs($n); # if negative was too big - $len--; $n = $len if $n > $len; # n to big? - - my $elem = int($n / $BASE_LEN); # which array element - my $digit = $n % $BASE_LEN; # which digit in this element - $elem = '0' x $BASE_LEN . @$x[$elem]; # get element padded with 0's - substr($elem,-$digit-1,1); + $n += $len if $n < 0; # -1 last, -2 second-to-last + return 0 if $n < 0 || $n >= $len; + + my $elem = int($n / $BASE_LEN); # which array element + my $digit = $n % $BASE_LEN; # which digit in this element + substr("$x->[$elem]", -$digit-1, 1); } sub _zeros diff -ru Math-BigInt-1.96//t/bigintc.t Math-BigInt-1.96-patched//t/bigintc.t --- Math-BigInt-1.96//t/bigintc.t 2010-09-13 16:28:42.000000000 +0200 +++ Math-BigInt-1.96-patched//t/bigintc.t 2010-10-01 13:46:31.839617600 +0200 @@ -129,9 +129,11 @@ is ($C->_digit($x,0),9); is ($C->_digit($x,1),8); is ($C->_digit($x,2),7); +is ($C->_digit($x,12),0); is ($C->_digit($x,-1),1); is ($C->_digit($x,-2),2); is ($C->_digit($x,-3),3); +is ($C->_digit($x,-12),0); # _copy foreach (qw/ 1 12 123 1234 12345 123456 1234567 12345678 123456789/)