in reply to Re: Find prime number between 1 to 1000000
in thread Find prime number between 1 to 1000000

That's a rather inefficent sieve. Inefficient in the sense that it wastes a lot of memory - it uses a single bit for every number, including all the even ones. That's half the memory usage for numbers you know cannot be prime. I've done sieves based on vec as well, and I've found that the limit on how far you can feasibly go is the memory consumption. Note that any prime number (except the first few) are of the form 30 * n + k with k one of 1, 7, 11, 13, 17, 19, 23, 29. (All other numbers are either divisible by 2, 3 or 5). Which means you need only 8 bits for every 30 numbers. Of course, more efficient packings exist as well.

Replies are listed 'Best First'.
Re^3: Find prime number between 1 to 1000000
by ELISHEVA (Prior) on Jul 29, 2009 at 15:36 UTC

    That was also my first reaction, but merlyn's algorithm is lightening fast. As is often the case, one trades speed for memory. On modern computers the amount of memory needed to find primes between 1 and 1 million is rarely an issue. The OP is satisfied with the primes < 1 million. If you are looking for very, very large primes (10's of digits) I'm sure other slower algorithms might be better.

    Best, beth

      No, merlyn was fast because of clever bit-twiddling. Not a good algorithm.

      The simple optimization of special casing 2 will result in doubling the speed of his algorithm.

      Just to demonstrate this to you, here is the prime generating code that I use for Project Euler problems:

      my @primes = (2, 3, 5, 7, 11); # None have been tested sub more_primes { # This adds to the list of primes until it reaches $max # or the square of the largest current prime (assumed odd) my $base = shift || $primes[-1]+1; my $max = shift || $base + 10_000; my $square = $primes[-1] * $primes[-1]; $max = $square if $square < $max; # Determine what to find prime +s to $base++ unless $base % 2; # Make the base odd $max-- if $max %2; # Make the max odd $max = ($max - $base)/2; # Make $max into a count of od +ds return if $max < 0; # Sanity check my $more = ""; # Initialize vector of 0's for + the # odd numbers in our range shift @primes; # Remove 2 foreach my $p (@primes) { my $start; if ($base < $p * $p) { $start = ($p * $p - $base)/2; # Start at the square if ($max < $start) { # Rest of primes don't matter! last; } } else { # Start at first odd it divide +s $start = $base % $p; # Find remainder $start = $p - $start if $start; # Distance to first thing it d +ivides $start += $p if $start %2; # Distance to first odd it div +ides $start = $start/2; # Reindex for counting over od +d! } for (my $i = $start; $i <= $max; $i += $p) { vec($more, $i, 1) = 1; } } unshift @primes, 2; # Replace 2 # Read off list of primes push @primes, map {$_ + $_ + $base} grep {vec($more, $_, 1) == 0} 0. +.$max; } sub ith_prime { my $i = shift; while ($i > $#primes) { more_primes(); } return $primes[$i]; } sub prime_iterator { my $i = -1; return sub { $i++; if ($i > $#primes) { more_primes(); } return $primes[$i]; }; }
      And an example of some code using this:
      my $iter = prime_iterator(); my $count = 0; $count++ while $iter->() < 1000000; print $count;
      On my laptop my code runs in 0.585s while merlyn's code runs in 1.188s.

      Note that I could make this code a third faster by special casing 3. But I haven't done this because the prime generating code has never yet been a bottleneck for me. I can generate all of the primes up to 50,000,000 in 33.932s.

      However if you need to generate primes *very* quickly, look up http://cr.yp.to/primegen.html. It bit twiddles better than merlyn, uses a better algorithm and is written in C for massively greater efficiency. Seriously, piping input from this program is much, much faster than anything you can do in Perl.