in reply to Why is this code so much slower than the same algorithm in C?

ptoulis's comment about stack-oriented loop structures got me thinking. What if the inner loop were replaced with individual lines of code? Here's what I came up with:
sub new { my $i = 0; while ($i += 20) { next if ($i % 1); next if ($i % 2); next if ($i % 3); next if ($i % 4); next if ($i % 5); next if ($i % 6); next if ($i % 7); next if ($i % 8); next if ($i % 9); next if ($i % 10); next if ($i % 11); next if ($i % 12); next if ($i % 13); next if ($i % 14); next if ($i % 15); next if ($i % 16); next if ($i % 17); next if ($i % 18); next if ($i % 19); print "Number: $i\n"; last; } }
Then I benchmarked it against your original Perl code and got these results:
s/iter original new original 25.7 -- -63% new 9.57 168% --
Admittedly, it doesn't scale very well and this example is very case specific, but I'll be paying closer attention to where and how I use loops from now on.

Replies are listed 'Best First'.
Re^2: Why is this code so much slower than the same algorithm in C?
by snowhare (Friar) on Dec 10, 2008 at 16:58 UTC
    With a little analysis to omit test values that don't affect the answer and some improvement on the if..next..if..next logic, I was able to tighten that up slightly:
    #!/usr/bin/perl use integer; my $i = 0; while ($i += 20) { last unless ($i % 3 or $i % 6 or $i % 7 or $i % 8 or $i % 9 or $i % 11 or $i % 12 or $i % 13 or $i % 14 or $i % 15 or $i % 16 or $i % 17 or $i % 18 or $i % 19 or $i % 20); } print "Number: $i\n";
      snowhare,
      Can this be reduced even further?
      for values of x > 20 if x % 12 == 0 then x % 6 == 0
      Is there a reason to have them both?

      Update: In other words, order the list in descending order removing any exact multiples of previous items. When you reach 16, one of two things will happen. Either there will be a remainder and it will exit the loop or there won't be a remainder and it will continue. There is no need to test 8 after 16.

      Cheers - L~R

        perl -le "do { $i += 20 } while( $i%3||$i%7||$i%11||$i%13||$i%16||$i%1 +7||$i%19 ); print $i" 77597520
        or just
        perl -le "print 3*5*7*11*13*16*17*19"

        Update: Replace 3 with 9 in both samples above to get the correct answer, as noted and further explained in the replies below.

        - tye        

        Good catch.
        #!/usr/bin/perl use integer; my $i = 0; while ($i += 20) { last unless ( $i % 19 or $i % 18 or $i % 17 or $i % 16 or $i % 15 or $i % 14 or $i % 13 or $i % 12 or $i % 11 ); } print "Number: $i\n";
        Is 17% faster than my original version.