Re: counting backward
by BrowserUk (Patriarch) on Mar 02, 2013 at 14:46 UTC
|
Because the range operator is defined as low .. high and as 10 is higher than 0, it does nothing.
There are a couple of ways of doing what you want:
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.
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
Which is okay for small ranges; but creates a huge list for large ones.
:) seems like an easy candidate for optimization , since this is optimized for (reverse @a) is optimized
perl -le " @f = 1 .. 100_000; for(reverse @f ){ $f=$_; $f==$#f and sca
+lar<> } "
perl -le " @f = 1 .. 100_000; for( @f ){ $f=$_; $f==$#f and scalar<> }
+ "
| [reply] [Watch: Dir/Any] [d/l] |
|
But you still had to create a huge array in order to benefit from the optimisation; which kinda negates the purpose.
This: perl -E"@a=1..1e9; for( reverse @a ) { print $_; <> }" consumes 18GB (that's Gigabytes!) of memory
Whereas this: perl -E"for( -1e9..1 ) { print -$_; <> }" iterates the same range and consumes only 1.8MB of ram.
Four orders of magnitude more memory, or a minus sign. My choice is simple; how about yours?
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.
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
|
|
AFAIK for( @f ) is optimized to act like an iterator without expanding and caching the list.
But in for(reverse @f ) there is no for-context which helps reverse to act differently.
I'm to lazy for benchmarks (we had them before), but this was surely not fixed in 5.8.8
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
|
|
|
|
|
|
Re: counting backward
by Athanasius (Archbishop) on Mar 02, 2013 at 16:44 UTC
|
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,
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
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;
}
}
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
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.
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
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.
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
Re: counting backward
by tobyink (Canon) on Mar 03, 2013 at 18:55 UTC
|
use strict;
use warnings;
foreach (my $i = 11; $i --> 0;)
{
print "$i ";
}
print "\n";
package Cow { use Moo; has name => (is => 'lazy', default => sub { 'Mooington' }) } say Cow->new->name
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
#! 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,
c_for_loop2 => \&c_for_loop2,
c_for_loop3 => \&c_for_loop3,
c_for_loop4 => \&c_for_loop4,
};
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;
}
}
sub c_for_loop2 {
for (my $j = $n; $j-- > 0; ) {
# $null->print( $j );
1;
}
}
sub c_for_loop3 {
for (my $j = $n; --$j > 0; ) {
# $null->print( $j );
1;
}
}
sub c_for_loop4 {
for (my $j = $n; --$j; ) {
# $null->print( $j );
1;
}
}
__END__
C:\test>junk
Rate c_for_loop2 c_for_loop c_for_loop3 foreach_loo
+p c_for_loop4 foreach_modifier
c_for_loop2 807/s -- -13% -38% -50
+% -53% -56%
c_for_loop 926/s 15% -- -29% -43
+% -46% -50%
c_for_loop3 1298/s 61% 40% -- -19
+% -24% -29%
foreach_loop 1612/s 100% 74% 24% -
+- -6% -12%
c_for_loop4 1707/s 111% 84% 31% 6
+% -- -7%
foreach_modifier 1839/s 128% 99% 42% 14
+% 8% --
But still the modifier form wins.
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.
| [reply] [Watch: Dir/Any] [d/l] |
Re: counting backward
by jms53 (Monk) on Mar 02, 2013 at 14:51 UTC
|
perl -e 'print "$_ " for (reverse (0..10))'
should work, although not necesarily the most intuitive solution.
| [reply] [Watch: Dir/Any] [d/l] |
|
Heh, I wasn't even asking about the solutions - more about why an inline reverse operator wasn't part of the implementation (somewhat answered quoting the doc) and why this didn't present a warning.
That said, I love the conversation and seeing foreach (-$var .. 0) { -$_ } - the memory use of reverse and the simplicity of the solution made me say 'damn'.
| [reply] [Watch: Dir/Any] |