Y'know, until now, I never noticed that "d/l code" anchor right below the "comment on this" anchor. The things you learn every day...
Suggestions subroutine by subroutine...
getmatrix: Pre-defining $input to 1 to prime the while,
then checking for valid input at the bottom after you have read it
is a little hard to understand. You could accomplish the same thing
by making the read from <STDIN> as part of the while,
with <while ($input = <STDIN>). That would allow
you to eliminate the $input &&... at the end as well.
Going one step further, every use of $input at that point is in locations
that default to $_, so you can eliminate it all together.
I'd recommend, for clarity sake, also renaming @input to @matrix,
since that's what it is.
sub getmatrix {
my $what = shift;
my @matrix;
while (<STDIN>) {
chop;
if (/^0-9 ]/) die "Not a legal matrix row!\n"; }
push @matrix, split / /;
}
return @matrix;
}
checkmatrix: This is short enough that there really isn't much to
suggest for improvement. The one thing I would suggest, though is
moving the $rowlength assignment out of the loop. First, for clarity,
second for efficiency. That and get rid of @row, it's unnecessary.
And I just noticed... ne is for string comparison, not
numeric. Since you are dealing with numbers, use !=.
sub checkmatrix {
my $rowlength = @$_[0];
for (@_) {
$rowlength == @$_ or die "Number of columns was not consistant!\n"
+;
}
}
As a matter of style, I'd have this return some boolean
value rather than simply up and dying. It allows the
caller to decide what to do with a broken matrix.
printmatrix: If that's how you want to format matrices,
good enough for me. Not much to criticize here. (This included for
completeness).
getdimen: This is really not clear what you are doing.
Obviously, you wanted to get the number of rows and columns, but
it seems a round-about way to get them. Especially the for loop
with an unguarded last, meaning the loop will execute only once. Not clear at all.
I'll do a total rewrite:
sub getdimen {
my $rows = @_; # get number of rows
my $cols = @$_[0]; # get number of elems in first row
return ($rows,$columns);
}
getproduct: This is the heart of your routine. The
major thing I'll mention here is that you can do something
like $product[$i][$j] += $a[$i][$k]*$b[$k][$j]; directly,
and perl will DWIM correctly. You don't even need to pre-initialize
@product. Using that would make your matrix multiply
much simpler to understand. This also eliminates most of your
"temp" variables.
The other thing I'd do is make product responsible for validating
it's arguments and extracting the info it needs directly, rather
than expect it to be called in.
sub getproduct {
my ($aref, $bref) = @_;
my @a = @$aref; my @b = @$bref;
my @product;
checkmatrix(@a);
checkmatrix(@b);
my ($arow, $acol) = getdimen(@a);
my ($brow, $bcol) = getdimen(@b);
$acol == $brow or die "The matrices can't be multiplied!\n";
for $i (0..$arow) {
for $j (0..$bcol) {
for $k (0..$acol) {
$product[$i][$j] += $a[$i][$k] * $b[$k][$j];
}
}
}
return @product;
}
Now, if I got the multiplication wrong, it's easy to see what
my mistake was (I haven't done linear algebra in a while, I might
have the rows/columns mixed up, for instance).
Perl is very good at having the features that DWIM when you need
them to. Trying to go overboard with pushes, temp arrays, etc
are not necessarily the way to go. As a general rule, I'd
say that if you have to force it to do what you want, there
might be an easier way...
Hope this helps... |