Reputation: 17542
I am making a Sieve of Eratosthenes implementation in Python. A problem that occurs is not all primes appear (mainly the lower numbered ones).
Here is my code:
def prevPrimes(n):
from math import sqrt
from time import time
start = time()
if type(n) != int and type(n) != long:
raise TypeError("Arg (n) must be of <type 'int'> or <type 'long'>")
if n <= 2:
raise ValueError("Arg (n) must be at least 2")
limit, x, num, primes = sqrt(n), 2, {}, []
for i in range(1, n+1):
num[i] = True
while x < limit:
for i in num:
if i%x==0:
num[i] = False
x += 1
for i in num:
if num[i]:
primes.append(i)
end = time()
primes = sorted(primes)
print round((end - start), 2), ' seconds'
return primes
If I input >>> prevPrimes(1000)
, I would expect the result to start out as: [2, 3, 5, 7, 11, 13, 17]
etc. However, this is what it looks like: [1, 37, 41, 43, 47, #more numbers]
.
I know that the issue lies in the fact that it is stating the 'original' primes (2, 3, 5, 7, 11, 13, 17, etc.) as False
because of the way my program checks for the primes. How can I avoid this? Thanks in advance :)
Upvotes: 0
Views: 233
Reputation: 175
import time
def primes_sieve1():
limitn = int(raw_input("Please enter an upper limit ")) +1
start = time.clock()
primes = {
}
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
end = time.clock()
print "This took ",end-start," seconds"
return [i for i in primes if primes[i]==True]
primes_sieve1()
Instead of using division this code takes the multiples of all numbers less than the root of the limit and changes them to false. This is somewhat quicker as it does not involve dividing every number by some other number.
Also below 1000 the situation occurs whereby a prime will be modulo ed by itself to give 0 and so the program will think it is false. Since the sqrt(1000) is roughly 31, primes less than 31 will be affected.
For example on the 7th loop of "while x < limit" the situation occurs such that: 7%7 == 0 and so 7 will appear to be false in your program. This will happen for all primes less than the limit of the "while x < limit" loop as x will at some point be a prime you are trying to find.
Upvotes: 0
Reputation: 17866
First, the answer to your specific question. You are discarding the primes less than the square root of n. The easiest fix is to change the line num[i] = False
to num[i] = (not x == i)
at the end of your inner loop (I think that works, I haven't tested it).
Second, your algorithm is trial division, not the Sieve of Eratosthenes, and will have time complexity O(n^2) instead of O(n log log n). The modulo operator gives the game away. The simplest Sieve of Eratosthenes looks like this (pseudocode, which you can translate into Python):
function primes(n)
sieve := makeArray(2..n, True)
for p from 2 to n step 1
output p
for i from p+p to n step p
sieve[i] := False
There are ways to improve that algorithm. If you're interested in programming with prime numbers, I modestly recommend this essay, which includes an optimized Sieve of Eratosthenes with implementation in Python.
Upvotes: 1
Reputation: 2155
So that wasn't an actual SoE implementation, one I wrote a while ago is below.
number_primes = 10
prime_list = [True]*number_primes
for i in range (2, number_primes): #check from 2 upwards
if prime_list[i]: #If not prime, don't need to bother about searching
j = 2
while j*i < number_primes: # Filter out all factors of i (2...n * prime)
prime_list[j*i] = False
j+=1
Upvotes: 1
Reputation: 60130
Sometimes when you iterate through num
, x
is equal to i
, so i % x
equals 0, and i
gets marked as a non-prime.
You need to add if not x == i:
somewhere in your while loop, e.g.:
while x < limit:
for i in num:
if not x == i:
if num[i] and i%x==0:
num[i] = False
Upvotes: 1