Re: How can I make my prime number generator better?



nikolas.britton@xxxxxxxxx (nikolas.britton@xxxxxxxxx) wrote on MMMMCMLII
September MCMXCIII in <URL:news:1174610848.316977.94170@xxxxxxxxxxxxxxxxxxxxxxxxxxxx>:
@@ How can I improve my code?... faster, better style, proper programming
@@ techniques, better algorithm? Thanks!

A better algorith beats everything else.

If you want to generate prime numbers starting from 1, sieves are your
best option. They have been your best option since antiquity.

Here's an example of a sieve:


#!/opt/perl/bin/perl -l

# A sieve based on base 6. Only possible primes are those numbers p
# for which p mod 6 == 1, or p mod 6 == 5.
#
# Let n = 6 * k + l (0 <= l < 6). Then the bit b associated with n is
# b = 2 * k + [undef, 0, undef, undef, undef, 1] -> [l]
# In reverse, given a bit b, the corresponding number n is
# n = 6 * int (b / 2) + [1, 5] -> [b % 2].

use strict;
use warnings 'all';

sub scrub ($);
sub findnext ($);

my $max = $ARGV [0] || 1000;

my @PRIMES = (2, 3);
my $BASE = 6; # LCM of @PRIMES.
my $BITS_BASE = 2;
my $BITS_BYTE = 8;

my $bits = $BITS_BASE * int ($max / $BASE) + ($max % $BASE ? $BITS_BASE : 0);
my $bytes = int ($bits / $BITS_BYTE) + ($bits % $BITS_BYTE ? 1 : 0);
my $sieve = eval qq !"\xFF" x $bytes!; # Half the memory usuage.

# Numbers less than the base are special.
foreach my $prime (@PRIMES) {
print $prime
}

my $i = 5;

for (; $i && $i <= sqrt ($max); $i = findnext $i) {
print $i;
scrub $i;
}

for (; $i && $i < $max ; $i = findnext $i) {
print $i;
}

exit;




my ($offset1, $offset2);
INIT {
$offset1 = [undef, 0, undef, undef, undef, 1];
$offset2 = [1, 5];
}

# Scrub out all multiples of the given argument. It's easy to see that
# all multiples less than the square already have been crossed out, and
# we only have to scrub out the odd multiples.
sub scrub ($) {
use integer;
my $n = shift;
my $m = $n;
if ($m % 3 == 1) {
my $c = $n * $m;
vec ($sieve, $BITS_BASE * ($c / $BASE) + $offset1 -> [$c % $BASE],
1) = 0;
$m += 4;
}

my $c = $n * $m;

# $b is the bit index in the sieve, $b1 and $b2 are the increments
# in the loop.
my $b = $BITS_BASE * ($c / $BASE) + $offset1 -> [$c % $BASE];
my $b1 = (2 * $n / ($BASE / $BITS_BASE));
my $b2 = (4 * $n / ($BASE / $BITS_BASE));

# Exactly one of $b1, $b2 needs to be incremented by 1,
# depending on the parity of $c.
($c % 6 == 1 ? $b2 : $b1) += 1;

# Make sure we don't go out of range.
my $l = $bits - $b1 - $b2;

# Core loop, we want to minimize work here.
while ($b <= $l) {
vec ($sieve, $b, 1) = 0; $b += $b1;
vec ($sieve, $b, 1) = 0; $b += $b2;
}

# Basically a copy of the previous loop, but with extra checks.
# Checks don't hurt now as this loop is performed only once.
{
last if $b > $bits;
vec ($sieve, $b, 1) = 0; $b += $b1;
last if $b > $bits;
vec ($sieve, $b, 1) = 0; $b += $b2;
}
}

# Find the next prime number after the given number.
sub findnext ($) {
use integer;
my $n = shift;
my $i = $BITS_BASE * ($n / $BASE) + $offset1 -> [$n % $BASE] + 1;
while ($i <= $bits) {
if (vec ($sieve, $i, 1)) {
return $BASE * ($i / $BITS_BASE) + $offset2 -> [$i % $BITS_BASE]
}
$i ++
} undef;
}


__END__
--
print 74.117.115.116.32, 97.110.111.116.104.101.114.32,
80.101.114.108.32, 72.97.99.107.101.114.10;
.



Relevant Pages

  • How to write a efficient Sieve of Eratosthenes algorithm in lisp?
    ... the ultimate test is to find primes in range 999900000 - ... Also, my sieve algorithm is n log, so even if the space ... Is there a way to optimize the lisp code below in a similar way? ... (loop for x from (start-index n) ...
    (comp.lang.lisp)
  • Re: [Full-disclosure] Internet Explorer Crash
    ... client-side to run a loop through so many itterations. ... Bonus points for defining isprime() as "Sieve of Eratosthenes" rather than some ... (Hint - "trusted site" is probably not the greatest way to phrase that sort ...
    (Full-Disclosure)
  • Re: Fast efficient way to test a small number for primality?
    ... >public boolean IsPrime(long testPrime) ... I am not sure what you mean about the Sieve of Eratosthenes. ... composite and 1 for a prime. ... loop this test is only useful once so it is best to move it outside. ...
    (comp.programming)
  • Re: Parsing challenge to reduce blanks
    ... > I replaced my forall with a do loop and amazing enuf it ran slower (using ... Scrub that result, when I increased the iterations x 10, the do loop was ...
    (comp.lang.fortran)
  • Re: Tool to convert NULLs to default values? Too tough?
    ... If this is too tough, maybe somebody can tell me how to just loop through ... Dave ... > table's columns looking for data to scrub. ...
    (microsoft.public.sqlserver.server)