3

Hi can anyone tell me how to implement Sieve of Eratosthenes within this code to make it fast? Help will be really appreciated if you can complete it with sieve. I am really having trouble doing this in this particular code.

#!/usr/bin/env python
import sys

T=10 #no of test cases
t=open(sys.argv[1],'r').readlines()

import math
def is_prime(n):
    if n == 2:
        return True
    if n%2 == 0 or n <= 1:
        return False
    sqr = int(math.sqrt(n)) + 1
    for divisor in range(3, sqr, 2):
        if n%divisor == 0:
            return False
    return True

#first line of each test case
a=[1,4,7,10,13,16,19,22,25,28]
count=0
for i in a:

    b=t[i].split(" ")
    c=b[1].split("\n")[0]
    b=b[0]

    for k in xrange(int(b)):
        d=t[i+1].split(" ")

        e=t[i+2].split(" ")
        for g in d:
            for j in e:
                try:
                    sum=int(g)+int(j)
                    p=is_prime(sum)         
                    if p==True:
                        count+=1
                        print count
                    else:
                        pass
                except:
                    try:
                        g=g.strip("\n")
                        sum=int(g)+int(j)
                        p=is_prime(sum)
                        if p==True:
                            count+=1
                            print count
                        else:
                            pass
                    except:
                        j=j.strip("\n")
                        sum=int(g)+int(j)
                        p=is_prime(sum)
                        if p==True:
                            count+=1
                            print count
                        else:
                            pass

print "Final count"+count
Will Ness
  • 62,652
  • 8
  • 86
  • 167
user2876096
  • 33
  • 1
  • 1
  • 4
  • related: [Fastest way to list all primes below N in python](http://stackoverflow.com/q/2068372/4279) – jfs Mar 06 '14 at 21:14

6 Answers6

12

An old trick for speeding sieves in Python is to use fancy ;-) list slice notation, like below. This uses Python 3. Changes needed for Python 2 are noted in comments:

def sieve(n):
    "Return all primes <= n."
    np1 = n + 1
    s = list(range(np1)) # leave off `list()` in Python 2
    s[1] = 0
    sqrtn = int(round(n**0.5))
    for i in range(2, sqrtn + 1): # use `xrange()` in Python 2
        if s[i]:
            # next line:  use `xrange()` in Python 2
            s[i*i: np1: i] = [0] * len(range(i*i, np1, i))
    return filter(None, s)

In Python 2 this returns a list; in Python 3 an iterator. Here under Python 3:

>>> list(sieve(20))
[2, 3, 5, 7, 11, 13, 17, 19]
>>> len(list(sieve(1000000)))
78498

Those both run in an eyeblink. Given that, here's how to build an is_prime function:

primes = set(sieve(the_max_integer_you_care_about))
def is_prime(n):
    return n in primes

It's the set() part that makes it fast. Of course the function is so simple you'd probably want to write:

if n in primes:

directly instead of messing with:

if is_prime(n):
Tim Peters
  • 55,793
  • 10
  • 105
  • 118
  • Thanks for the answer but now when primes are generated. they are not compared with the sum of numbers in list so the whole code is faster. – user2876096 Oct 14 '13 at 10:02
  • code is faster then before thanks a lot. But the sum part and compare part is still slow :( – user2876096 Oct 14 '13 at 11:56
  • @user2876096, if you need more help, I think you should open a new question, showing the exact code you're using **now**. *This* question was about using a sieve, and has already been answered ;-) – Tim Peters Oct 14 '13 at 17:34
  • 1
    thanks I got it working. Now it solves 50000x50000 lists in 7 minutes :) Thanks a lot all for help. – user2876096 Oct 16 '13 at 22:07
  • @Tim Peters Thank you for the excellent answer! For the purpose of this sieve sqrtn = int(n**0.5) should be enough, right? – Ajay Yadav May 22 '15 at 04:12
  • 1
    @Ajay Yadav, better safe than sorry. For example, consider `n=169`. Exponentiation is implemented by taking a logarithm under the covers, multiplying by the power, and then raising the base of the logarithm to that result. Depending on platform math library quirks, 169**0.5 _may_ come out to, say, 13.000000000001 or to 12.99999999999 instead of exactly 13.0. Using `round()` instead of `int()` guards against that (`int(12.99999999)` would return 12, not the 13 needed here). – Tim Peters May 22 '15 at 04:33
10

Both the original poster and the other solution posted here make the same mistake; if you use the modulo operator, or division in any form, your algorithm is trial division, not the Sieve of Eratosthenes, and will be far slower, O(n^2) instead of O(n log log n). Here is a simple Sieve of Eratosthenes in Python:

def primes(n): # sieve of eratosthenes
    ps, sieve = [], [True] * (n + 1)
    for p in range(2, n + 1):
        if sieve[p]:
           ps.append(p)
           for i in range(p * p, n + 1, p):
               sieve[i] = False
    return ps

That should find all the primes less than a million in less than a second. If you're interested in programming with prime numbers, I modestly recommend this essay at my blog.

user448810
  • 16,364
  • 2
  • 31
  • 53
1

Fastest implementation I could think of

def sieve(maxNum):
    yield 2
    D, q = {}, 3
    while q <= maxNum:
        p = D.pop(q, 0)
        if p:
            x = q + p
            while x in D: x += p
            D[x] = p
        else:
            yield q
            D[q*q] = 2*q
        q += 2
    raise StopIteration

Source: http://code.activestate.com/recipes/117119-sieve-of-eratosthenes/#c4

Replace this part

import math
def is_prime(n):
    if n == 2:
        return True
    if n%2 == 0 or n <= 1:
        return False
    sqr = int(math.sqrt(n)) + 1
    for divisor in range(3, sqr, 2):
        if n%divisor == 0:
            return False
    return True

with

primes = [prime for prime in sieve(10000000)]
def is_prime(n):
    return n in primes

Instead of 10000000 you can put whatever the maximum number till which you need prime numbers.

thefourtheye
  • 206,604
  • 43
  • 412
  • 459
0

Here is a very fast generator with reduced memory usage.

def pgen(maxnum): # Sieve of Eratosthenes generator
    yield 2
    np_f = {}
    for q in xrange(3, maxnum + 1, 2):
        f = np_f.pop(q, None)
        if f:
            while f != np_f.setdefault(q+f, f):
                q += f
        else:
            yield q
            np = q*q
            if np < maxnum:  # does not add to dict beyond maxnum
                np_f[np] = q+q

def is_prime(n):
    return n in pgen(n)

>>> is_prime(541)
True
>>> is_prime(539)
False
>>> 83 in pgen(100)
True
>>> list(pgen(100)) # List prime numbers less than or equal to 100
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83,
89, 97]
dansalmo
  • 10,338
  • 5
  • 50
  • 49
0

Here is a simple generator using only addition that does not pre-allocate memory. The sieve is only as large as the dictionary of primes and memory use grows only as needed.

def pgen(maxnum): # Sieve of Eratosthenes generator
    pnext, ps = 2, {}
    while pnext <= maxnum:
        for p in ps:
            while ps[p] < pnext:
                ps[p] += p
            if ps[p] == pnext:
                break
        else:
            ps[pnext] = pnext
            yield pnext
        pnext += 1

def is_prime(n):
    return n in pgen(n)

>>> is_prime(117)
>>> is_prime(117)
False
>>> 83 in pgen(83)
True
>>> list(pgen(100)) # List prime numbers less than or equal to 100
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83,
89, 97]
dansalmo
  • 10,338
  • 5
  • 50
  • 49
0

This is a simple solution with sets. Which is very fast in comparison with many of the list-algorithms. Computation with sets is much faster because of the hash tables. (What makes sets faster than lists in python?)

Greetings

----------------------------------
from math import *

def sievePrimes(n):

    numbers = set()
    numbers2 = set()
    bound = round(sqrt(n))

    for a in range(2, n+1):
        numbers.add(a)

    for i in range(2, n):
        for b in range(1, bound):
            if (i*(b+1)) in numbers2:
                continue
            numbers2.add(i*(b+1))
    numbers = numbers - numbers2

    print(sorted(numbers))

Simple Solution

Community
  • 1
  • 1