我正在用Python制作一个Eratosthenes的Sieve实现。出现的问题并非所有素数都出现(主要是编号较低的素数)。
这是我的代码:
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
如果我输入>>> prevPrimes(1000)
,我希望结果开头为:[2, 3, 5, 7, 11, 13, 17]
等。但是,这就是它的样子:[1, 37, 41, 43, 47, #more numbers]
。
我知道问题在于它将{原始'素数(2,3,5,7,11,13,17等)称为False
因为我的方式程序检查素数。我怎么能避免这个?在此先感谢:)
答案 0 :(得分:1)
有时,当您遍历num
时,x
等于i
,因此i % x
等于0,i
被标记为非素数
您需要在while循环中的某处添加if not x == i:
,例如:
while x < limit:
for i in num:
if not x == i:
if num[i] and i%x==0:
num[i] = False
答案 1 :(得分:1)
所以这不是一个真正的SoE实现,我刚才写的是下面的。
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
答案 2 :(得分:1)
首先,回答您的具体问题。您丢弃的素数小于 n 的平方根。最简单的解决方法是在内循环结束时将行num[i] = False
更改为num[i] = (not x == i)
(我认为这样做有效,我还没有对其进行测试)。
其次,您的算法是试验分区,而不是Eratosthenes的Sieve,并且将具有时间复杂度O(n ^ 2)而不是O(n log log n)。模运算符让游戏消失。最简单的Eratosthenes Sieve看起来像这样(伪代码,你可以把它翻译成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
有很多方法可以改进该算法。如果您对素数编程感兴趣,我谦虚地推荐this essay,其中包括一个优化的Eratosthenes Sieve,并在Python中实现。
答案 3 :(得分:0)
导入时间
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()
此代码不是使用除法,而是将所有数字的倍数小于限制的根,并将它们更改为false。这有点快,因为它不涉及将每个数字除以其他数字。
同样低于1000的情况会发生这样的情况,即素数将自己模数为0,因此程序会认为它是假的。由于sqrt(1000)大约为31,因此小于31的素数将受到影响。
例如,在“while x&lt; limit”的第7个循环中,出现这样的情况: 7%7 == 0,因此在您的程序中7将显示为false。对于低于“while x&lt; limit”循环限制的所有素数,都会发生这种情况,因为x在某些时候会是你想要找到的素数。