Beefy Boxes and Bandwidth Generously Provided by pair Networks
Do you know where your variables are?
 
PerlMonks  

Re: counting backward

by Athanasius (Archbishop)
on Mar 02, 2013 at 16:44 UTC ( [id://1021450]=note: print w/replies, xml ) Need Help??


in reply to counting backward

I’m a little surprised no-one has suggested a good, old-fashioned, C-style for loop. If speed is a factor, it’s a clear winner over foreach-with-negation:

#! perl use strict; use warnings; use Benchmark qw( cmpthese ); my $n = 1e4; cmpthese ( 100, { foreach_loop => \&foreach_loop, c_for_loop => \&c_for_loop, } ); sub foreach_loop { for my $i (-$n .. 0) { print -$i; } } sub c_for_loop { for (my $j = $n; $j >= 0; --$j) { print $j; } }

Output (end only):

Rate foreach_loop c_for_loop foreach_loop 89.0/s -- -69% c_for_loop 292/s 227% -- 2:32 >

Hope that helps,

Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

Replies are listed 'Best First'.
Re^2: counting backward
by vagabonding electron (Curate) on Mar 03, 2013 at 16:33 UTC

    It seems that your output and the output of BrowserUk brings the different results ( Re^5: counting backward (optimize foreach reverse low .. high ).

    I noticed that you print in the loop and BrowserUk calls '1'. I tried to run the both versions and found that it brings the different results indeed:

    Loops with print (I used a NULL device to keep it clear, s.below): Rate foreach_loop c_for_loop foreach_loop 256/s -- -8% c_for_loop 278/s 8% -- Loops with '1': Rate c_for_loop foreach_loop c_for_loop 1314/s -- -22% foreach_loop 1674/s 27% --
    The code (your code :-):
    #! perl use strict; use warnings; use IO::Null; =pod PM Thread perlquestion [id://1021418] =cut use Benchmark qw( cmpthese ); my $n = 1e4; my $null = IO::Null->new; cmpthese ( 10000, { foreach_loop => \&foreach_loop, c_for_loop => \&c_for_loop, } ); sub foreach_loop { for my $i (-$n .. 0) { # $null->print( -$i ); 1; } } sub c_for_loop { for (my $j = $n; $j >= 0; --$j) { # $null->print( $j ); 1; } }

      You caught that I use 1; as the body of the loop to avoid confusing things with the efficiency of the system null device driver (not particularly efficient on Win32). But you missed the point I was trying to make; namely that you cannot use the C-style for as a modifier; which means you must always pay the penalty of creating a new scope for each iteration of the loop.

      Add that to the benchmark to see that cost:

      #! perl use strict; use warnings; #use IO::Null; use Benchmark qw( cmpthese ); my $n = 1e4; #my $null = IO::Null->new; cmpthese 10000, { foreach_loop => \&foreach_loop, foreach_modifier => \&foreach_modifier, c_for_loop => \&c_for_loop, }; sub foreach_loop { for my $i (-$n .. 0) { # $null->print( -$i ); 1; } } sub foreach_modifier { 1 for -$n .. 0; } sub c_for_loop { for (my $j = $n; $j >= 0; --$j) { # $null->print( $j ); 1; } } __END__ C:\test>junk Rate c_for_loop foreach_loop foreach_modi +fier c_for_loop 922/s -- -41% +-52% foreach_loop 1573/s 71% -- +-18% foreach_modifier 1922/s 108% 22% + --

      Of course, some people eschew the use of modifier forms; but then they are probably the same people that favor their own one-off developer time over the every-user, every-time runtime costs.

      As for much of my work I am both user and developer, I don't have that luxury.


      With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      "Science is about questioning the status quo. Questioning authority".
      In the absence of evidence, opinion is indistinguishable from prejudice.

      vagabonding electron,

      You are correct that a foreach loop is faster than a C-style for loop, other things being equal. As BrowserUk has explained, this is because with the latter, but not the former,

      you must always pay the penalty of creating a new scope for each iteration of the loop.

      But my point was that if you count upwards from -$n, you add the overhead of a unary negation operator when you come to actually use the original $n:

      #! perl use strict; use warnings; use Benchmark qw( cmpthese ); my $n = 1e6; my $foreach_loop_total = 0; my $c_for_loop_total = 0; cmpthese ( 1000, { foreach_loop => \&foreach_loop, c_for_loop => \&c_for_loop, } ); print "\$foreach_loop_total = $foreach_loop_total\n"; print "\$c_for_loop_total = $c_for_loop_total\n"; sub foreach_loop { $foreach_loop_total += -$_ for -$n .. 0; } sub c_for_loop { for (my $j = $n; $j >= 0; --$j) { $c_for_loop_total += $j; } }

      Output:

      12:00 >perl 555_SoPW.pl Rate foreach_loop c_for_loop foreach_loop 5.62/s -- -8% c_for_loop 6.13/s 9% -- $foreach_loop_total = 500000500000000 $c_for_loop_total = 500000500000000 12:05 >

      So, it appears that the overhead of the additional negation outweighs the benefit of not having to create a new scope on each iteration.

      Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

        There are still plenty more ways to skin that cat :)

        Why subtract and add; when you can just subtract. And why compare to zero when it is unnecessary:

        #! perl use strict; use warnings; use Benchmark qw( cmpthese ); my $n = 1e6; my $foreach_loop_total = 0; my $c_for_loop_total = 0; my $while_loop_total = 0; my $while_loop_total2 = 0; cmpthese 100, { foreach_loop => \&foreach_loop, c_for_loop => \&c_for_loop, while_loop => \&while_loop, while_loop2 => \&while_loop2, }; print "\$foreach_loop_total = $foreach_loop_total\n"; print "\$c_for_loop_total = $c_for_loop_total\n"; print "\$while_loop_total = $while_loop_total\n"; print "\$while_loop_total2 = $while_loop_total2\n"; sub foreach_loop { $foreach_loop_total -= $_ for -$n .. 0; } sub c_for_loop { for (my $j = $n; $j >= 0; --$j) { $c_for_loop_total += $j; } } sub while_loop { my $n = $n; $while_loop_total += $n-- while $n; } sub while_loop2 { use integer; my $n = $n; $while_loop_total2 += $n-- while $n; } __END__ C:\test>junk Rate c_for_loop while_loop while_loop2 foreach_loo +p c_for_loop 4.94/s -- -22% -39% -44 +% while_loop 6.31/s 28% -- -22% -28 +% while_loop2 8.07/s 63% 28% -- -8 +% foreach_loop 8.76/s 77% 39% 8% - +- $foreach_loop_total = 50000050000000 $c_for_loop_total = 50000050000000 $while_loop_total = 50000050000000 $while_loop_total2 = 50000050000000

        With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://1021450]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others sharing their wisdom with the Monastery: (4)
As of 2024-04-25 06:54 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found