Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sieve of Eratosthenes - Finding Primes Python

Just to clarify, this is not a homework problem :)

I wanted to find primes for a math application I am building & came across Sieve of Eratosthenes approach.

I have written an implementation of it in Python. But it's terribly slow. For say, if I want to find all primes less than 2 million. It takes > 20 mins. (I stopped it at this point). How can I speed this up?

def primes_sieve(limit):     limitn = limit+1     primes = range(2, limitn)      for i in primes:         factors = range(i, limitn, i)         for f in factors[1:]:             if f in primes:                 primes.remove(f)     return primes  print primes_sieve(2000) 

UPDATE: I ended up doing profiling on this code & found that quite a lot of time was spent on removing an element from the list. Quite understandable considering it has to traverse the entire list (worst-case) to find the element & then remove it and then readjust the list (maybe some copy goes on?). Anyway, I chucked out list for dictionary. My new implementation -

def primes_sieve1(limit):     limitn = limit+1     primes = dict()     for i in range(2, limitn): primes[i] = True      for i in primes:         factors = range(i,limitn, i)         for f in factors[1:]:             primes[f] = False     return [i for i in primes if primes[i]==True]  print primes_sieve1(2000000) 
like image 442
Srikar Appalaraju Avatar asked Oct 15 '10 05:10

Srikar Appalaraju


People also ask

How do you find prime numbers using Sieve of Eratosthenes?

The Sieve of Eratosthenes method is easy to use. We need to cancel all the multiples of each prime number beginning with 2 (including the number 1, which is not a prime or composite) and encircle the rest of the numbers. The encircled numbers will be the required prime numbers.

How do you generate primes in Python?

To find a prime number in Python, you have to iterate the value from start to end using a for loop and for every number, if it is greater than 1, check if it divides n. If we find any other number which divides, print that value.


2 Answers

You're not quite implementing the correct algorithm:

In your first example, primes_sieve doesn't maintain a list of primality flags to strike/unset (as in the algorithm), but instead resizes a list of integers continuously, which is very expensive: removing an item from a list requires shifting all subsequent items down by one.

In the second example, primes_sieve1 maintains a dictionary of primality flags, which is a step in the right direction, but it iterates over the dictionary in undefined order, and redundantly strikes out factors of factors (instead of only factors of primes, as in the algorithm). You could fix this by sorting the keys, and skipping non-primes (which already makes it an order of magnitude faster), but it's still much more efficient to just use a list directly.

The correct algorithm (with a list instead of a dictionary) looks something like:

def primes_sieve2(limit):     a = [True] * limit                          # Initialize the primality list     a[0] = a[1] = False      for (i, isprime) in enumerate(a):         if isprime:             yield i             for n in range(i*i, limit, i):     # Mark factors non-prime                 a[n] = False 

(Note that this also includes the algorithmic optimization of starting the non-prime marking at the prime's square (i*i) instead of its double.)

like image 194
Pi Delport Avatar answered Oct 10 '22 08:10

Pi Delport


def eratosthenes(n):     multiples = []     for i in range(2, n+1):         if i not in multiples:             print (i)             for j in range(i*i, n+1, i):                 multiples.append(j)  eratosthenes(100) 
like image 26
Saurabh Rana Avatar answered Oct 10 '22 08:10

Saurabh Rana