Confusing performance results for prime

Patrick Ellis pellis.nospam at tampabay.rr.com
Sun Oct 19 01:43:50 EDT 2003


"Greg Brunet" <gregbrunet at NOSPAMsempersoft.com> wrote in message
news:vp3liuqs76bd5a at corp.supernews.com...
> Thanks for the responses!  After some more testing based on the
> responses I got, here's some additional notes:
>
> <snipped the notes>

Here are some functions from an earlier discusion. Note that 1 and 2
are faster, but more memory intensive. They create a list (or array)
of all odd numbers and weed out the non-primes. 3 and 1ix only
create the primes, saving a lot of space.

==================================================

from __future__ import generators
import Numeric
import math
import sys
import time

# Basically, Tim Peter's version of sieve.
def sieve1(n):
    if n < 2:
        return []
    limit = int(math.sqrt(n))
    primes = range(1, n+1, 2)
    primes[0] = 0
    n = len(primes)
    for p in primes:
        if not p: continue
        if p > limit: break
        # note that p*p is odd, so no need to subtract 1
        # before shifting right -- same thing in the end
        for i in xrange((p*p)>>1, n, p):
            primes[i] = 0
    primes[0] = 2
    return filter(None, primes)

# The same as sieve1, but modified by me to use numeric for more speed.
def sieve2(n):
    if n < 2:
        return []
    primes = Numeric.arrayrange(1, n+1, 2)
    limit = (int(math.sqrt(n)) / 2) + 1
    for p in primes[1:limit]:
        if p:
            # note that p*p is odd, so no need to subtract 1
            # before shifting right -- same thing in the end
            primes[(p*p)>>1::p] = 0
    return list(Numeric.nonzero(primes))

# Not sure where this came from, but I am sure I didn't write it. This is
# a generator, the function is below.
def sieve3gen(maximum):
    "Generate all primes <= maximum."
    if maximum >= 2:
        yield 2
    if maximum >= 3:
        yield 3
    # candidate takes on all integer values > 3 that aren't divisible by
    # 2 or 3.
    candidate = 5
    delta = 2  # flips between 2 and 4
    # Map i to (d, 6*p), where d is 2*p or 4*p, p is a prime dividing i,
    # and i+d is the next multiple of p larger than i not divisible by
    # 2 or 3.  As the algorithm proceeds, f will contain one entry for
    # each prime <= sqrt(maximum) discovered so far (excepting 2 and 3).
    f = {}
    fetch = f.pop
    adding = candidate**2 <= maximum
    while candidate <= maximum:
        if candidate in f:
            d, s = fetch(candidate)
            # candidate + d is next multiple of s/6 that isn't divisible
            # by 2 or 3
            i = candidate + d
            d = s-d
            while i in f:
                i += d
                d = s-d
            f[i] = d, s
        else:
            yield candidate
            if adding:
                sq = candidate**2
                f[sq] = delta * candidate, 6 * candidate
                adding = sq <= maximum
        candidate += delta
        delta = 6 - delta

# Convert the generator into a function that matches the others.
def sieve3(n):
    return [i for i in sieve3gen(n)]

# One of the algorithms from this thread, for comparison.
# test using list of primes - w/ int typecast and xrange
# (to see if xrange is faster - no noticable difference)
def Primes1ix(y):
    primes = [3]
    for p in xrange(5, y, 2):
        limit = int(math.sqrt(p))
        for factor in primes:
            if factor > limit:      # then number is prime
                primes.append(p)
                break
            elif p % factor == 0:   # then it's *not* prime
                break
    return [2] + primes


if __name__ == "__main__":
    n=1000000
    if len(sys.argv) > 1:
        n = int(sys.argv[1])

    times = []
    primes = []
    for pfun in (sieve1, sieve2, sieve3, Primes1ix):
        tb = time.time()
        p = pfun(n)
        primes.append(len(p))
        dt = time.time() - tb
        times.append(dt)
    fastest = min(times)

    print 'Prime number algorithms/optimizations - up to:', n
    if (fastest==0):
        print '*** Percentages are invalid (fastest time is 0) ***'
        fastest = .01
    for i, pfun in enumerate((sieve1, sieve2, sieve3, Primes1ix)):
        print '%s: %s primes up to %s in %5.3f secs (+%3.1f%%)' % (
            pfun.__name__, primes[i], n, times[i],
            (times[i]-fastest)*100/fastest)

===================================================

Prime number algorithms/optimizations - up to: 1000000
sieve1: 78498 primes up to 1000000 in 0.593 secs (+99.7%)
sieve2: 78498 primes up to 1000000 in 0.297 secs (+0.0%)
sieve3: 78498 primes up to 1000000 in 1.078 secs (+263.0%)
Primes1ix: 78498 primes up to 1000000 in 10.438 secs (+3414.5%)






More information about the Python-list mailing list