This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
RT ticket #61812: digit($n) with $n "out of range"
authorPeter John Acklam <pjacklam@online.no>
Thu, 4 Nov 2010 17:08:56 +0000 (18:08 +0100)
committerFlorian Ragwitz <rafl@debian.org>
Sun, 7 Nov 2010 15:15:22 +0000 (16:15 +0100)
The _digit($n) method in Math::BigInt::Calc should return 0 when $n
refers to a leading zero digit. E.g., the number '314' is just the
same as '000314', except that the leading zeros omitted, so _digit($n)
should return '0' when $n refers to a leading zero digit.

- lib/Math/BigInt/Calc.pm: Improve comments in source code. Add code
  returning zero when input refers to a leading zero digit. Removed
  redundant zero padding in temporary string argument to substr().

- t/bigintc.t: Add four test cases verifying the behaviour. Increment
  number of test by four.

dist/Math-BigInt/lib/Math/BigInt/Calc.pm
dist/Math-BigInt/t/bigintc.t

index f5f4ff1..af638f2 100644 (file)
@@ -1206,20 +1206,18 @@ sub _len
 
 sub _digit
   {
-  # return the nth digit, negative values count backward
-  # zero is rightmost, so _digit(123,0) will give 3
+  # 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 ($c,$x,$n) = @_;
 
   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;   # return 0 for digits out of range
+
+  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
index 9b94aeb..3123ff8 100644 (file)
@@ -1,7 +1,7 @@
 #!/usr/bin/perl -w
 
 use strict;
-use Test::More tests => 375;
+use Test::More tests => 379;
 
 use Math::BigInt::Calc;
 
@@ -129,9 +129,13 @@ $x = $C->_new("123456789");
 is ($C->_digit($x,0),9);
 is ($C->_digit($x,1),8);
 is ($C->_digit($x,2),7);
+is ($C->_digit($x,8),1);
+is ($C->_digit($x,9),0);
 is ($C->_digit($x,-1),1);
 is ($C->_digit($x,-2),2);
 is ($C->_digit($x,-3),3);
+is ($C->_digit($x,-9),9);
+is ($C->_digit($x,-10),0);
 
 # _copy
 foreach (qw/ 1 12 123 1234 12345 123456 1234567 12345678 123456789/)