Three other techniques come to mind:
$val=$val+0; # Sum
$val=eval "$val"; # Eval
$val=sprintf("%f", $val); # Sprintf
# Call your original technique "Regex"
Experimenting with the four techniques (using the subroutines
defined in the code below) shows that none of them is perfect.
This is because Sum, Regex and Eval ultimately rely on how Perl
interprets the resulting number. And perl sometimes will return
scientific notation, so in those cases Sum, Regex and Eval
will return exactly the same number. For example:
Sum("1.25e-5") gives '1.25e-05'
Regex("1.25e-5") '1.25e-05'
Eval("1.25e-5") '1.25e-05'
Sum("1.25e-3") 0.00125
Regex("1.25e-3") 0.00125
Eval("1.25e-3") 0.00125
So you can see that whenever perl would return scientific notation,
these three methods return the same number. Now, using Sprintf:
Sprintf("1.25e-5") 0.000013
Sprintf("1.25e-3") 0.001250
Sprintf("1.25e-7") 0.000000
This method always expands the number, but its disadvantage
is that it always returns a fixed number of digits. Of course,
you can always use something like:
sprintf("%.10f", $val) 0.0012500000
Which gives you the trailing zeros. So finally you can use
something like the SprintfSubst function below, which uses
sprintf with a large precision and then eliminates the trailing
zeros.
The performance figures for the script below on my Ultra 1 are:
Benchmark: timing 100000 iterations of Eval, Regex, Sprintf, SprintfSu
+bst, Sum...
Eval: 20 wallclock secs (19.58 usr + 0.00 sys = 19.58 CPU)
Regex: 9 wallclock secs ( 9.97 usr + 0.00 sys = 9.97 CPU)
Sprintf: 7 wallclock secs ( 6.22 usr + 0.00 sys = 6.22 CPU)
SprintfSubst: 8 wallclock secs ( 8.74 usr + 0.00 sys = 8.74 CPU)
Sum: 4 wallclock secs ( 3.52 usr + 0.00 sys = 3.52 CPU)
Sum is by far the fastest, so if you are dealing with "normal"
(not too small, not too large) numbers, that's the best way to
go. Regex, Sprintf and SprintfSubst are very close together,
and SprintfSubst is the one that works with any number.
Just some food for thought :-)
--ZZamboni
Here's the code used above:
#!/usr/bin/perl
use Benchmark;
sub Regex {
my $val=shift;
$val =~ s/([\.\d]+)e([-+]?\d+)/$1*10**$2/egi;
return $val;
}
sub Eval {
my $val=shift;
$val=eval " $val ";
return $val;
}
sub Sum {
my $val=shift;
$val=$val+0;
return $val;
}
sub Sprintf {
my $val=shift;
$val=sprintf("%f",$val);
return $val;
}
sub SprintfSubst {
my $val=shift;
$val=sprintf("%.10f", $val);
$val=~s/0*$//;
return $val;
}
timethese(100000, { Regex => sub { Regex("1.25e-3") },
Eval => sub { Eval("1.25e-3") },
Sum => sub { Sum("1.25e-3") },
Sprintf => sub { Sprintf("1.25e-3") },
SprintfSubst => sub { SprintfSubst("1.25e-3") },
});
|