Beefy Boxes and Bandwidth Generously Provided by pair Networks
The stupid question is the question not asked
 
PerlMonks  

sprintf vs. substr (for zero-padded values)

by Theseus (Pilgrim)
on Jul 15, 2002 at 19:49 UTC ( #181893=perlquestion: print w/replies, xml ) Need Help??

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

I was fooling around with Benchmark a bit earlier, and I found that substr seems to be slightly(not much, but slightly) faster than sprintf for creating zero-padded numbers. So my question is this... Why use sprintf? Is there any reason other than ease of use?

Please note that this question ONLY applies to creating zero-padded numbers, I understand why you would need to use sprintf for other purposes.

Benchmark code below:

use Benchmark; timethese(1000000, { 'Method one' => '&one', 'Method two' => '&two' } +); sub one { my $number = "213"; my $padded = sprintf("%09d",$number); #print $padded,"\n"; # the above line is only uncommented when # benchmarking with 1 loop to test to make # sure resulting number is what we want } sub two { my $number = "213"; my $padded = "000000000"; my $length = length($number); substr($padded,(-$length),$length,$number); #print $padded,"\n"; }

Replies are listed 'Best First'.
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.
      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.
        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.
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:??;

      Because math scares me. ;)
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}

Re: sprintf vs. substr (for zero-padded values)
by fglock (Vicar) on Jul 15, 2002 at 20:22 UTC

    another way to do it:

    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"

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

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

      Good question, Abigail... But that's a whole new can of worms. Something for Meditations on a rainy day, perhaps. ;)
        I disagree it's a new can of worms. I think that both questions have the same answer.

        Abigail

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;

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://181893]
Approved by tadman
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others exploiting the Monastery: (2)
As of 2019-12-08 02:18 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    Strict and warnings: which comes first?



    Results (162 votes). Check out past polls.

    Notices?