Re: sprintf vs. substr (for zero-padded values)
by tadman (Prior) on Jul 15, 2002 at 20:38 UTC
|
If it's only slightly faster, I'd say stay the heck away from rewriting sprintf. You're just asking for trouble, anyway. In four lines of code you already have a nasty bug:
sub one {
my ($number) = @_;
my $padded = sprintf("%09d",$number);
$padded;
}
sub two {
my ($number) = @_;
my $padded = "000000000";
my $length = length($number);
substr($padded,(-$length),$length,$number);
$padded;
}
print one(-6),"\n"; # -00000006
print two(-6),"\n"; # 0000000-6
print one(43/6),"\n"; # 000000007
print two(43/6),"\n"; # 7.16666666666667
It's just not worth the hassle to patch these bugs when sprintf is already sea-worthy. | [reply] [d/l] [select] |
|
|
Ahh... Admittedly, I didn't run that code through the mill looking for bugs, only drew it up quickly to benchmark it. Good catch, now I guess I know why people use sprintf for this even though it's a bit slower.
| [reply] |
|
|
Here's the thing. It's not slower. It's actually faster, but your benchmark wasn't constructed properly. You used a constant, which I think Perl was optimizing away. Also, you were burying sprintf within a relatively expensive function call. Take a look at this:
use Benchmark qw[cmpthese];
sub one {
sprintf("%09d",@_);
}
sub two {
substr("000000000$_[0]",-9);
}
cmpthese(100, {
one => sub { for(0..10000) { $_ = one($_) } },
two => sub { for(0..10000) { $_ = two($_) } },
tre => sub { for(0..10000) { $_ = sprintf("%09d", $_) } },
});
__DATA__
Benchmark: timing 100 iterations of one, tre, two...
one: 12 wallclock secs (10.63 usr + 0.00 sys = 10.63 CPU) @ 9
+.41/s (n=100)
tre: 3 wallclock secs ( 3.38 usr + 0.00 sys = 3.38 CPU) @ 29
+.59/s (n=100)
two: 12 wallclock secs (11.08 usr + 0.00 sys = 11.08 CPU) @ 9
+.03/s (n=100)
Rate two one tre
two 9.03/s -- -4% -69%
one 9.41/s 4% -- -68%
tre 29.6/s 228% 214% --
You're correct in your assumption that substr is faster, so long as the only number you need to process is "213" and you bury it in a subroutine call. You'll have to admit that in the real world users tend to ask for a little more functionality than that.
It would seem that sprintf wins by a knockout.
| [reply] [d/l] |
|
|
|
|
Re: sprintf vs. substr (for zero-padded values)
by japhy (Canon) on Jul 15, 2002 at 20:06 UTC
|
Why not use 1 + int(log($number)/log(10)) in place of length(), if you can be sure you're using positive integers? ;)
_____________________________________________________
Jeff[japhy]Pinyan:
Perl,
regex,
and perl
hacker, who'd like a job (NYC-area)
s++=END;++y(;-P)}y js++=;shajsj<++y(p-q)}?print:??; | [reply] [d/l] [select] |
|
|
Because math scares me. ;)
| [reply] |
Re: sprintf vs. substr (for zero-padded values)
by thelenm (Vicar) on Jul 15, 2002 at 20:16 UTC
|
For me, anyway, the goal is not always the absolute fastest performance possible (if it were, maybe I would write more programs in C). In this case, all else being equal, I would probably use sprintf over substr. I think that's mostly because the code is easier for me to understand at a glance. When I come back to this snippet of code a few months from now, it will take me longer to understand what the substr is doing.
Also, sprintf has functionality specifically intended for what we're using it for. It seems like we have to play with substr a little bit to get it to do what we need it to. If we have to use this code more than once, we'll either have to remember how we massaged substr and do it the exact same way again, or else put the substr solution in a subroutine of its own. Which is fine, but a little more effort.
To me anyway, the substr hoops are a little too large for me to jump through for a mere 2-3% gain in performance. But it could easily be that there are performance-critical applications for which the substr solution would be appropriate.
-- Mike
--
just,my${.02} | [reply] [d/l] [select] |
Re: sprintf vs. substr (for zero-padded values)
by fglock (Vicar) on Jul 15, 2002 at 20:22 UTC
|
sub three {
my $number = "213";
return '0' x (9 - length($number)) . $number;
}
Update: you might want to test/benchmark this
before thinking it is "good" | [reply] [d/l] |
Re: sprintf vs. substr (for zero-padded values)
by ferrency (Deacon) on Jul 15, 2002 at 20:43 UTC
|
Note that a more accurate benchmark of one and two above would test numbers of all lengths, not just three digits. One method may be faster or slower for shorter or longer numbers.
I'm inclined to agree that the speed difference would most likely be small enough that it wouldn't be the primary deciding factor for me in this case. I prefer the sprintf method for ease of implementation and maintenance. If you add in the cost of calling an encapsulated zero-padder instead of printf, your times may be even closer.
Alan | [reply] |
Re: sprintf vs. substr (for zero-padded values)
by Abigail-II (Bishop) on Jul 16, 2002 at 11:59 UTC
|
Let me answer your question with another.
I was fooling around with a benchmark program a bit earlier, and I found
that C seems to be much (not slightly, but much) faster than Perl for
about anything. So my question is this... Why use Perl? Is there any
reason other than ease of use?
Abigail | [reply] |
|
|
Good question, Abigail... But that's a whole new can of worms. Something for Meditations on a rainy day, perhaps. ;)
| [reply] |
|
|
I disagree it's a new can of worms. I think that both
questions have the same answer.
Abigail
| [reply] |
Re: sprintf vs. substr (for zero-padded values)
by dada (Chaplain) on Jul 16, 2002 at 11:38 UTC
|
if you're looking for speed (and you know $number is always less than 10 digits), why not do it this way:
sub three {
my $number = "213";
my $padded = substr("000000000".$number, -9);
#print $padded,"\n";
}
cheers,
Aldo
__END__
$_=q,just perl,,s, , another ,,s,$, hacker,,print;
| [reply] [d/l] [select] |