rbi has asked for the
wisdom of the Perl Monks concerning the following question:

Hi,
I have translated a program from FORTRAN to perl.
When I run it as FORTRAN-compiled executable, it is at least 4 times faster than perl,
on input files of about 120000 records.
Since I'm a beginner, I'm sure the perl I've written is not very good...
In particular, in (1) I prepare a $tmp string through a loop to be printed.
the subroutine decode might have problems too... I've replicated the FORTRAN code and there I compute the exponential, but maybe string manipulation can do much better...
Thanks in advance for any corrections/suggestions
Roberto

Wow, there's nothing quite like FORTRAN in Perl. :) My sympathies, I have to do a lot of this too.

First of all, let me say that if your goal is to make the Perl code run as fast
as the FORTRAN code, then stick with FORTRAN. If your goal is to get away from
FORTRAN's miserable excuses for text handling, then welcome to Perl and you're on the
right track.

As for what could be better: the first thing that jumped out to me was to replace the loop in decode
with combinations of unpack and map. The only tricky bit is that you have to build
the template string for unpack on the fly, since we don't know the number of values in advance. If I read the code correctly, something like this would work:

I had thought there might be a faster way to do this with map, but all of my
answers seem contrived and convoluted, especially considering how much conditional
code there is per item. If you're learning your way around
Perl, try getting this or something similar going first, then look at a more idiomatic approach.

Is it possible to change the format of the data? If so, a simpler algorithm
could greatly improve the speed.

TheoPetersen seems to be on the right path. One thing
he showed, but didn't mention was that in your code you
tend to build your loops with
foreach $it (1..$nt)
and then subtract one each time you use $it. A lot of
calculations can be saved just by
foreach $it <0..$nt-1)
That will save some time, but getting away from nested
loops will save you more.

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 :

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 :

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.
---

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 quite liked this problem at first, and like TheoPetersen my
reaction was to try unpack and map. Adding unpack was easy, and
I even squeezed in a map or two, but not avoiding a for loop.
Now the strange thing is that all my efforts are actually slower
than rbi's original. I'll add code if anyone wants but it's
basically what was posted here:

Alba_1 is almost exactly TheoPetersen's solution (I didn't bother posting after seeing his)
Alba_2 is a variant that does the unpacking this way:

Thanks for the answers and comments so far.
I did test all the suggestions too, and I found that the things were worsening about 20% (no profiles, I still have to learn that, just used ps...) with:
1. use of unpack (quite clean coding though)
2. extracting the strings from $record and "printing" the exponetial format with, more or less, this code:

When putting a smiley right before a closing parenthesis, do you:

Use two parentheses: (Like this: :) )
Use one parenthesis: (Like this: :)
Reverse direction of the smiley: (Like this: (: )
Use angle/square brackets instead of parentheses
Use C-style commenting to set the smiley off from the closing parenthesis
Make the smiley a dunce: (:>
I disapprove of emoticons
Other