我正在使用Python2.7
在我编写的Eratosthenes ()和erat2()的两个实现中,erat2()的优点是在第二次运行erat2()时,它会在较短的时间内给出结果。
def erat2(num, isprime = [2]):
if num > len(isprime) + 2:
last_original = len(isprime) + 2
isprime += [num for num in xrange(last_original ,num + 1)]
for i in xrange(2,num + 1):
if isprime[i-2]:
if i <= last_original:
j = last_original//i + 1
else:
j = 2
temp = j * i
while temp <= num:
isprime[temp-2] = 0
j += 1
temp = j * i
return filter(lambda x: x != 0, isprime[:num - 1])
def erat(num):
isprime = [num for num in xrange(2,num + 1)]
for i in xrange(2,num + 1):
if isprime[i-2]:
j = 2
temp = j * i
while temp <= num:
isprime[temp-2] = 0
j += 1
temp = j * i
return filter(lambda x: x != 0, isprime)
import time
def t():
num = 100000000
i = 10
while i < num:
s = time.time()
erat2(i)
x = time.time() - s
print "%10d %10f" %(i,x),
s = time.time()
erat(i)
y = time.time() - s
print " %10f" %(y)
i *= 10为了支持这样一个事实,即在第二次运行代码时,结果会更快,这里给出了一些时间分析。第一列是测试输入。第二列用于erat2()的定时,第三列用于erat()的定时。很明显,第二轮的时间减少了7倍。
>>> t()
10 0.000000 0.000000
100 0.000000 0.000000
1000 0.000000 0.000000
10000 0.010000 0.010000
100000 0.100000 0.110000
1000000 1.231000 1.410000
10000000 13.605000 15.081000
>>> t()
10 0.000000 0.000000
100 0.000000 0.000000
1000 0.000000 0.000000
10000 0.000000 0.020000
100000 0.020000 0.140000
1000000 0.170000 1.550000
10000000 1.770000 15.752000我面临的问题是,在这个测试输入之后,内存使用量急剧上升。
编辑:
我发现了对erat()和erat2()这两个函数的一些优化,以提高速度。将lambda函数改为
lambda x: x != 0至
lambda x: x同样的结果,但速度稍快。对于num = 10000000,快1秒。
EDIT2:
使用了vartec和btilly的建议。将erat()改进为erat3()。下面是改进的实现以及定时检查。还发现在xrange函数中放置表达式会导致性能损失。添加变量以提高性能。
def erat3(num):
''' Improves Sieve of eratosthenes '''
#REQUIRES MATH MODULE
if num < 2:
return []
isprime = [num for num in xrange(3,num + 1,2)]
#temp2's expression placed in xrange function => performance-loss
temp2 = int(math.sqrt(num)) + 1
for i in xrange(3, temp2 ,2):
if isprime[(i-3)/2]:
j = 3
temp = j * i
while temp <= num:
isprime[(temp-3)/2] = 0
j += 2
temp = j * i
return [2] + filter(lambda x: x, isprime)erat()和erat3()的定时
>>> t()
10 0.000000 0.000000
100 0.000000 0.000000
1000 0.000000 0.000000
10000 0.010000 0.010000
100000 0.110000 0.040000
1000000 1.241000 0.530000
10000000 14.131000 6.111000发布于 2013-06-03 19:48:20
在内存和性能之间进行权衡是很常见的。哪一个对你来说更重要取决于你的申请。
在这种情况下,我建议通过使用BitVector (详见https://pypi.python.org/pypi/BitVector )来减轻这种情况,这样您创建的数据结构就更加紧凑了。
此外,在这种情况下,特殊的大小写2和只存储奇数位将使性能加倍,并使内存减半,代价是代码复杂度略高一些。这可能是值得的
发布于 2013-06-03 19:48:57
您可以使用单比特作为isprime数组。Python并没有给出一种非常快速的操作比特的方法,但是有一种简单的方法是使用long。
is_prime = (1 << num) - 1并使用此方法检查是否筛选了一个数字。
is_prime & (1 << x)下面是如何在对第二个函数进行最小修改的情况下应用它
def erat(num):
isprime = (1 << num) - 1
for i in xrange(2,num + 1):
if isprime & (1 << i):
j = 2
temp = j * i
while temp <= num:
isprime &= (1 << num) - 1 - (1 << temp)
j += 1
temp = j * i
return [i for i in range(num) if isprime&(1 << i)]可能值得将(1 << num)存储在局部变量中,以节省一次又一次构建它。正如@btilly所指出的,只要做一点额外的工作,只需跟踪奇数,就可以节省一半的空间。
https://stackoverflow.com/questions/16904570
复制相似问题