Array index bug using concatenated numbers

J

John W. Krahn

I ran across this problem on the Perl beginners mailing list and am
posting here because I am not running the current version of Perl and
would like someone else to confirm this.

The following code should demonstrate the problem:

#!/usr/bin/perl
use warnings;
use strict;

use constant X => 99;
use constant Y => 99;
my @array;
my @check1;
my @check2;
my $diff = 0;

for my $x ( 0 .. X ) {
for my $y ( 0 .. Y ) {
my $i = 0 + ( $x . $y );
$array[ $i ] = int( rand ~0 );
push @check1, $array[ $i ];
}
}

for my $x ( 0 .. X ) {
for my $y ( 0 .. Y ) {
my $i = 0 + ( $x . $y );
push @check2, $array[ $i ];
if ( $check1[ $#check2 ] != $check2[ $#check2 ] ) {
print "$x . $y $check1[$#check2] $check2[$#check2]\n";
$diff++;
}
}
}

print "\n$diff differences from ", X, Y, " entries\n";

__END__

This _should_ print out "0 differences from 9999 entries" but on my
computer I get 900 differences. If I change "my $i = 0 + ( $x . $y );"
to "my $i = $x * 100 + $y;" it works correctly with 0 differences. This
looks like a bug in array indexing.

The original thread is at
http://groups.google.com/groups?threadm=4087A478.18574.7F3DCA@localhost


TIA
John
 
B

Bob Walton

John said:
I ran across this problem on the Perl beginners mailing list and am
posting here because I am not running the current version of Perl and
would like someone else to confirm this.

The following code should demonstrate the problem:

#!/usr/bin/perl
use warnings;
use strict;

use constant X => 99;
use constant Y => 99;
my @array;
my @check1;
my @check2;
my $diff = 0;

for my $x ( 0 .. X ) {
for my $y ( 0 .. Y ) {
my $i = 0 + ( $x . $y );
$array[ $i ] = int( rand ~0 );
push @check1, $array[ $i ];
}
}

for my $x ( 0 .. X ) {
for my $y ( 0 .. Y ) {
my $i = 0 + ( $x . $y );
push @check2, $array[ $i ];
if ( $check1[ $#check2 ] != $check2[ $#check2 ] ) {
print "$x . $y $check1[$#check2] $check2[$#check2]\n";
$diff++;
}
}
}

print "\n$diff differences from ", X, Y, " entries\n";

__END__

This _should_ print out "0 differences from 9999 entries" but on my
computer I get 900 differences. If I change "my $i = 0 + ( $x . $y );"
to "my $i = $x * 100 + $y;" it works correctly with 0 differences. This
looks like a bug in array indexing.

The original thread is at
http://groups.google.com/groups?threadm=4087A478.18574.7F3DCA@localhost
....


John

It appears like the "900 differences" result is correct. Consider
$array[1000], for example. It contains undef. That's because the
number 1000 was never made by the expression 0+($x.$y) -- there is not
combination of $x and $y in the range 0..99 which will make that
expression generate 1000. There are 10000 elements in @array, and 900
of them contain undef. That's because the subscript values for each of
these 900 elements were never generated in $i. This then implies that
some other element of @array was assigned each time -- specifically, 900
other elements got written twice (consider for example which element
gets written when $x is 0 and $y is 11 versus when $x is 1 and $y is 1).
So when @check2 is generated from @array, 900 array elements from
@array had different results in them than when the results were stored
in @check1. Thus 900 differences.

HTH.
 
T

Tassilo v. Parseval

Also sprach Purl Gurl:
John W. Krahn wrote:

(snipped)



I am curious about this syntax for rand.

Your ~0 is intended to perform what function?

~0 is the bitwise negation of, well, zero. If you have a 32bit wide
integer, zero is represented as 0 x 32. If you negate each bit, you
get 1 x 32 which is

0xff 0xff 0xff 0xff

and that gives 4294967295. For the 32bit case, this is ULONG_MAX.

'int( rand ~0 )' will therefore return a random integer in the range of
0 .. ULONG_MAX.

Tassilo
 
J

Joe Smith

John said:
for my $x ( 0 .. X ) {
for my $y ( 0 .. Y ) {
my $i = 0 + ( $x . $y );

Let's see; if $x = 1 and $y = 23, then $i = "123".
But then if $x = 12 and $y = 3, then $i = "123".
Therefore $array[$i] is going to get clobbered because you told it to.

As you noticed, changing the calculation of $i so that it does not
produce any duplicates makes the "problem" go away.

As does using proper indexing: $array[$x][$y] = "something";

I see no bug here.
-Joe
 
M

Michele Dondi

I am curious about this syntax for rand.

Your ~0 is intended to perform what function?

$ perl -MO=Deparse -le 'rand ~0'
BEGIN { $/ = "\n"; $\ = "\n"; }
rand 4294967295;
-e syntax OK

$ perldoc perlop


Michele
 
J

John W. Krahn

Joe said:
for my $x ( 0 .. X ) {
for my $y ( 0 .. Y ) {
my $i = 0 + ( $x . $y );

Let's see; if $x = 1 and $y = 23, then $i = "123".
But then if $x = 12 and $y = 3, then $i = "123".
Therefore $array[$i] is going to get clobbered because you told it to.

As you noticed, changing the calculation of $i so that it does not
produce any duplicates makes the "problem" go away.

As does using proper indexing: $array[$x][$y] = "something";

I see no bug here.

Thanks Joe, I really need to get more sleep, it should have been
obvious! :)


John
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top