This little snippet will print the first 'x' primes, with 'x' being a number supplied as the argument to the snippet (defaults to 10). It relies on Abigail-II's one-line prime number test and iterators as described in Dominus upcoming book.

#!/usr/bin/perl use warnings; use strict; sub NEXT ($) { $_[0]->() } sub prime_iterator { my $num = 0; sub { do { $num++; } until ( (1 x $num) !~ /^(11+)\1+$/); return $num; } } my $prime = prime_iterator; print NEXT $prime, "\n" for (1 .. shift || 10);

Replies are listed 'Best First'.
Re: Prime Iterator
by Anonymous Monk on Oct 24, 2002 at 21:12 UTC

      Hey, that looks pretty cool and I'll see what I can do to implement that, once I've worked out the math (it doesn't look too hard). In the meantime, here's a much faster version, easier to read version, based upon an article by merlyn.

      #!/usr/bin/perl use warnings; use strict; use Data::Dumper; sub NEXT ($) { $_[0]->() } sub prime_iterator { my $num = 0; sub { do { $num++; } until is_prime($num); return $num; } } sub is_prime { my $guess = shift; for (my $divisor = 2; $divisor * $divisor <= $guess; $divisor++) { return unless $guess % $divisor; } return 1; } my $prime = prime_iterator; my @primes; push @primes => NEXT $prime for (1 .. shift || 10); print Dumper \@primes;

      Cheers,
      Ovid

      Update: Here's a better "is_prime" function, based upon a code snippet provided in the link the greenback mentioned. This is twice as fast as the above function.

      sub is_prime { my $guess = shift; # accidentally reversed next two lines. Thanks to petral for catch +ing that :) return 1 if $guess == 2; return unless $guess > 2 and $guess % 2; my $max = 1 + int $guess ** .5; for ( my $divisor = 3; $divisor < $max; $divisor += 2 ) { return unless $guess % $divisor; } return 1; }

      Join the Perlmonks Setiathome Group or just click on the the link and check out our stats.

Re: Prime Iterator
by gjb (Vicar) on Oct 25, 2002 at 13:15 UTC

    It might help to replace the $num++ by $num += 2 since 2 is the only prime number that is even. This saves you half the tests for primality if you have 2 as a special case.

    Best, -gjb-

Re: Prime Iterator
by greenback (Initiate) on Oct 25, 2002 at 17:49 UTC
Re: Prime Iterator
by Anonymous Monk on Jan 01, 2003 at 20:09 UTC
    For the new year, a somewhat more efficient implementation using Euclid's algorithm. The recursively defined iterator is somewhat cool as well. Memory usage is reasonable...

    It would be faster were it not for the absurd function call overhead in Perl. :-(

    use strict; sub build_sieve { my $n = 0; my @upcoming_factors = (); my ($next_small_p, $sub_iter); my $gives_next_square = 5; return sub { LOOP: { if (not $n++) { return 2; # Special case } if (not defined $upcoming_factors[0]) { if ($n == $gives_next_square) { if (not defined ($sub_iter)) { # Be lazy to avoid an infinite loop... $sub_iter = build_sieve(); $sub_iter->(); # Throw away 2 $next_small_p = $sub_iter->(); } push @{$upcoming_factors[$next_small_p]}, $next_small_p; $next_small_p = $sub_iter->(); my $next_p2 = $next_small_p * $next_small_p; $gives_next_square = ($next_p2 + 1)/2; shift @upcoming_factors; redo LOOP; } else { shift @upcoming_factors; return 2*$n-1; } } else { foreach my $i (@{$upcoming_factors[0]}) { push @{$upcoming_factors[$i]}, $i; } shift @upcoming_factors; redo LOOP; } } } } my $sieve = build_sieve(); print $sieve->(), "\n" for 1..(shift || 100);