in reply to how can I speed this up?

This was quite a sizable snippet, so I downloaded it, and commented everything.
My first concern would be the number of loops you have, and their placement:
# for each of the 9 $nvars,
# for each of the $nts
# For each of the $nts...
# And the for each of the $nvars...
# for each of the $nts...
you loop through 2 variables 5 times. I believe that it'd be possible to compress this to one nested loop, or to use (look away, JAPHY :) an intermediary variable to store the results of parts of your loops.
Consider the following snippet ( I have removed my comments :
foreach $it (1..$nt) { $tmp = sprintf "%s", $some_vector[$it-1]; foreach $k (1..$nvar) { $tmp = $tmp.sprintf " %11.4E", $field[$it-1][$k-1]; } $tmp = $tmp."\n"; print OUT $tmp;
This loop follows one similar to it, though the inner and outer loops are swapped. Consider printing $tmp as the last step of the firstforeach $k (1..$nvar) loop.
Also, I might try a little trickery with perl's definition of scalar values when computing the powers. The following snippet "reproduces" 10**n without ever using **. Though, I confess I don't know what the benchmark would be. The following snippet shows how to get the same results. This is only good for powers of ten though :
#--- powers $ib=10; $x2 = 10.**($ib/2); print "$x2\n"; $x2 = "1". "0"x($ib/2); print "$x2\n"; #--- negative power $ib=3; $x2 = 10.**(-($ib+1)/2); print "$x2\n"; $x2 = "0." . "0"x int($ib-1)/2 ."1"; print "$x2\n";
I'd like to hear from some other monks on whether this may be speedier, though.

Finally, whenever I need to speed up code, I'll document it, and more often than not, something will jump out at me. I've included the comments I made while running through your code, and I hope they prove useful.
---
.... $nvar = 9; .... foreach $k (1..$nvar) { # # for each of the 9 $nvars, # $record = <IN>; chomp($record); # # I will read in a record and clear trailing newline. # @values = &decode($record,$nt,$val_m); # # I will 'decode' a record, using $nt and $val_m. # # # for each of the $nts # foreach $it (1..$nt) { # # if the $it'th-1 element of $values is less than one # and is not equal to $val_m, I will die. if ($values[$it-1] < 0 and $values[$it-1] != $val_m) + { die "error: found negative value.\n"; } $field[$it-1][$k-1] = $values[$it-1]; # # I will put $values[$it-1] into $field[$it-1][k-1]. # } } foreach $it (1..$nt) { # # For each of the $nts... # $tmp = sprintf "%s", $some_vector[$it-1]; # # I will format $some_vector[$it-1]. # foreach $k (1..$nvar) { # # And the for each of the $nvars... # $tmp = $tmp.sprintf " %11.4E", $field[$it-1][$k-1]; } $tmp = $tmp."\n"; print OUT $tmp; # # I'll format it and print it. # } # (2) this is seems to go the same speed as the one above ... # # foreach $it (1..$nt) { # printf OUT "%s", $some_vector[$it-1]; # foreach $k (1..$nvar) { # printf OUT " %11.4E", $field[$it-1][$k-1]; # } # print OUT "\n"; # } .... sub decode() { # this routine should decode the $record where there are a series of # $nt decimal fractions in the first part of the string # (5*$nt characters),and exponents in the last decimal fractions are # written as 5-digit integers, and must be multiplied by 10.**(-5), # negative exponents are coded as 2-digit odd numbers, while positive # exponents are even numbers # 12345...01... where 01 are characters $nt*5 and $nt*5+1 will give # 1.234E-01 my $record = shift(); my $nt = shift(); my $val_missing = shift(); $lmina = 0; $lminb = 5 * $nt; foreach $it (1..$nt) { # # for each of the $nts... # $ia = substr($record,$lmina,5); $ib = substr($record,$lminb,2); # # I'll set ia and ib to be certain substrings of $record # if ($ia == 0 and $ib == 99) { $values[$it-1] = $val_missing; # # if $ia is exactly zero, and $ib is exactly 99, set $values[$it-1] +to $val_missing. # } else { $x1 = $ia * 10.**(-5); # # otherwise, set $x1 to $ia times 10 to the negative fifth power. # if (($ib % 2) == 0) { $x2 = 10.**($ib/2); } else { $x2 = 10.**(-($ib+1)/2); } # # if $ib is evenly divisible by two, set $x2 to # 10 to the (half of $ib'th) power, # otherwise, set $x2 to the negative (half of $ib'th+1) power. # $values[$it-1] = $x1 * $x2; # # set $values [$it-1] to the sum of $x1 and $x2. # } $lmina = $lmina + 5; $lminb = $lminb + 2; # increase the position of $lmina and $lminb. } return @values; }

Replies are listed 'Best First'.
Re: (boo) Dissecting PerlTRAN
by Albannach (Monsignor) on Feb 24, 2001 at 01:50 UTC
    Just a quick note on the avoidance of the ** operator: I think as a general rule string manipulations are always far slower than math. I actually did try a variation on what you suggest myself (in a desperate quest for a better overall decode sub) and the benchmarks indicate the string route is very much slower (using 5 CPU sec run I went from 4800/sec to 4000/sec).

    Update: tilly kindly offered this clarification: "Math will normally be faster if it already is a number. But converting strings to numbers to use a math operation, then converting back can go either way because of the conversion operation. (Usually better though.)"

    Since this problem does boil down to getting strings, doing some math on them and spitting out strings, trying the all string manipulation approach could work if the math were just right.

    --
    I'd like to be able to assign to an luser