Python 在这些Eratosthenes筛的实现中,是否有一些方法可以降低内存需求

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

我正在使用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 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
我面临的问题是,在这个测试输入之后,内存使用量急剧增加

  • 是否可以进行一些优化以减少内存消耗
  • 这样增加内存是一种好的实现实践吗
编辑:

我发现对函数erat()和erat2()都进行了一些优化,以提高速度。将lambda函数从

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)]