Python 在这些Eratosthenes筛的实现中,是否有一些方法可以降低内存需求
我正在使用Python 2.7 在我编写的erat2()和erat2()的两个实现中,Eratosthenes erat()和erat2()的筛子有一个好处,即在第二次运行erat2()时,它以相对较少的时间给出结果Python 在这些Eratosthenes筛的实现中,是否有一些方法可以降低内存需求,python,memory,optimization,Python,Memory,Optimization,我正在使用Python 2.7 在我编写的erat2()和erat2()的两个实现中,Eratosthenes erat()和erat2()的筛子有一个好处,即在第二次运行erat2()时,它以相对较少的时间给出结果 def erat2(num, isprime = [2]): if num > len(isprime) + 2: last_original = len(isprime) + 2 isprime += [num for num in
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
我面临的问题是,在这个测试输入之后,内存使用量急剧增加
- 是否可以进行一些优化以减少内存消耗
- 这样增加内存是一种好的实现实践吗
lambda x: x != 0
到
结果相同,但速度稍快。如果num=10000000,则加快一秒
编辑2:
使用了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)
在内存和性能之间进行权衡是很常见的。哪个对你更重要取决于你的申请 在本例中,我建议通过使用位向量(有关详细信息,请参阅)来减轻这种情况,从而使您创建的数据结构更加紧凑
同样,在这种情况下,特殊的大小写2和仅存储奇数位将使性能加倍,内存减半,但代价是代码复杂度略高。这可能是值得的。您可以将单个位用于iPrime阵列。Python并没有提供一种真正快速的方法来操作位,但是一种简单的方法是使用长的
is_prime = (1 << num) - 1
is_prime=(1)要检查num
是否为素数,您只需检查它是否可被数字@vartec整除,这比生成素数的Eratosthenes筛慢得多number@gnibbler:我说的是筛子,如果你的循环达到num
,那么你生成的素数达到num**2
@vartec有助于优化。谢谢。自从我开始学习Python几周以来,我一直在努力添加新的软件包。我正在使用Windows 7,不知道如何安装这些软件包。对此有什么建议吗?我建议只存储奇数以改进erat()。这对优化它有很大帮助。erat2()变得太复杂了,我在尝试这样做时搞砸了。谢谢。好吧,你应该停止在sqrt(n)进行过滤
。这将是一个巨大的性能改进。至于位向量,您必须导入位向量
。这是否有效取决于您是否安装了位向量,我认为您将使用Python 3而不是Python 2安装它。(我没有Python 3,因此无法验证。)但是可以为Python 2下载,并且应该可以工作。在erat3()我使用极限sqrt(n)标记为复合。但是如果我停止在sqrt(n)处过滤,那么我就无法获得高达数字n(包括)的素数。我在遵循您使用的逻辑方面遇到了问题。您能解释一下吗?我已经发布了基于btily建议的编辑代码。如果我可以使用bits,那会更好。
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)
>>> 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
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)]