超过python中列表的大小

时间:2010-02-25 21:21:05

标签: python memory prime-factoring sieve-of-eratosthenes

我正在尝试在python中实现sieve of eratosthenes,但是当试图找到例如779695003923747564589111193840021的sqare根的所有素数时,我得到一个错误,说范围()的结果也是很多东西。我的问题是,我如何避免这个问题,如果我用while循环实例化列表,我会得到一个错误,说我使用了太多的内存(在它开始使用页面文件之前),下面列出了两个:

使用范围()

maxnum = 39312312323123123

primes = []
seq = []
i = 0
seq = range(2,maxnum)

for i in seq:
    mul = i * seq
    for j in mul:
        try:
            seq.remove(j)
        except:
            pass
        primes.append(i)

print primes

使用while:

maxnum = 39312312323123123

primes = []
seq = []
i = 0
while i < maxnum:
    seq.append(i)
    i+=1

for i in seq:
    mul = i * seq
    for j in mul:
        try:
            seq.remove(j)
        except:
            pass
        primes.append(i)

print primes

7 个答案:

答案 0 :(得分:6)

我会说,“使用xrange()代替”,但实际上你正在使用整数列表作为筛选结果.....所以整数生成器不是正确的解决方案。

我认为很难实现一个包含39312312323123123元素的列表,无论你使用什么函数这样做....毕竟,这是279 PB的64位整数。

试试这个。

class FoundComposite(Exception): pass

primes = [2]

seq = itertools.takewhile(        # Take integers from a list
          lambda x: x<MAXNUM,     #   until we reach MAXNUM
          itertools.count(2)      #   the list of integers starting from 2
          )

#seq = xrange(2, MAXNUM)          # alternatively

for i in seq:
    try:
        for divisor in primes:
            if not (i % divisor):
                # no remainder - thus an even divisor
                # continue to next i in seq
                raise FoundComposite 
        # if this is reached, we have tried all divisors.
        primes.append(i)
    except FoundComposite:
        pass

答案 1 :(得分:2)

你的算法坏了。首先让它工作maxnum = 100。

一旦你开始工作,你会发现maxnum = 100000000需要很长时间才能运行。

绘制在(10,100,1000,10000,100000,1000000 ...)中运行maxnum所需的时间你可能能够推断39312312323123123需要多长时间:)

答案 2 :(得分:2)

这是一个更复杂的算法,也许在技术上不算作筛子,但一种方法是不立即删除给定素数的所有倍数,而是排队下一个倍数(连同素数)。这可以用在生成器实现中。队列仍然会包含很多(多个)素数,但不会像构建然后过滤列表那样多。

手动完成前几个步骤,以显示原则......

  • 2是prime - yield和queue(4,2)
  • 3是素数 - 收益和队列(6,3)
  • 4是复合的 - 用队列中的(6,2)替换(4,2)
  • 5是prime - yield和queue(10,5)
  • 6是复合材料 - 用(8,2)代替(6,2)和(6,3)代替(9,3)

注意 - 队列不是FIFO。您将始终使用最低的第一项来提取元组,但新的/替换元组不会(通常)具有最高的第一项,并且(与上面的6一样)将存在重复项。

为了在Python中有效地处理队列,我建议使用由元组的第一项键控的字典(即散列表)。数据是一组第二项值(原始素数)。

正如其他地方所建议的那样,在尝试使用小型目标之前先测试一下小目标。如果你失败了也不要太惊讶。可能仍然需要一次(在队列中)需要太多堆分配的大整数来完成解决方案。

答案 3 :(得分:1)

python的第三方模块名为gmpy

它有一些对你有用的功能,因为它们非常快。概率性的东西大约在40亿大关。

next_prime(...)
    next_prime(x): returns the smallest prime number > x.  Note that
    GMP may use a probabilistic definition of 'prime', and also that
    if x<0 GMP considers x 'prime' iff -x is prime; gmpy reflects these
    GMP design choices. x must be an mpz, or else gets coerced to one.

is_prime(...)
    is_prime(x,n=25): returns 2 if x is _certainly_ prime, 1 if x is
    _probably_ prime (probability > 1 - 1/2**n), 0 if x is composite.
    If x<0, GMP considers x 'prime' iff -x is prime; gmpy reflects this
    GMP design choice. x must be an mpz, or else gets coerced to one.

答案 4 :(得分:0)

range()返回一个包含所请求范围内所有数字的列表,而xrange是一个生成器,并且一个接一个地产生数字,内存消耗接近于零。

答案 5 :(得分:0)

关于内存限制,如何创建内部是列表或数组的链接列表的自定义列表(类)。在内部巧妙地从一个遍历到另一个,并根据需要添加更多,因为调用者使用您提供的外部接口的自定义列表,这类似于促进.append .remove等需要的成员。你问题中使用的数组。

注意:我不是Python程序员。不知道如何实现我在Python中所说的内容。也许我不知道这里的背景,所以如果我被投票,我会理解。

也许使用“generators”因为它们在python中被调用以产生内部列表的结果,就像它是一个巨大的单个列表一样。可能是linked list

答案 6 :(得分:0)

试试这个:

def getPrimes(maxnum):
    primes = []
    for i in xrange(2, maxnum):
        is_mul = False
        for j in primes:         # Try dividing by all previous primes
            if i % j == 0:
                is_mul = True    # Once we find a prime that i is divisible by
                break            # short circuit so we don't have to try all of them
        if not is_mul:           # if we try every prime we've seen so far and `i`
            primes.append(i)     # isn't a multiple, so it must be prime
    return primes

在你获得大量素数之前,你不应该耗尽内存。这样您就不必担心创建多个列表。不确定这是否仍然算作筛子。

实际上,这对maxnum = 39312312323123123无效。使用Prime number theorem我们可以估计该范围内将有大约1,028,840,332,567,181个素数。

正如this question中所指出的,32位系统上python列表的最大大小为536,870,912。因此,即使你的内存不足,你仍然无法完成计算。

但是,对于64位系统,您不应该遇到这个问题。

2 ** 64 => 18446744073709551616

使用上述问题(2 ** 64) / 8中的数学,列表中元素的最大数量为2,305,843,009,213,693,951,大于您将遇到的估计素数。

修改

为避免内存问题,您可以将素数列表存储在硬盘上的文件中。每行存储一个素数,并在每次检查新号码时读取文件。

也许是这样的:

primes_path = r'C:\temp\primes.txt'

def genPrimes():
    for line in open(primes_path, 'r'):
        yield int(line.strip())    

def addPrime(prime):
    primes_file = open(primes_path, 'a')
    primes_file.write('%s\n' % prime)
    primes_file.close()

def findPrimes(maxnum):
    for i in xrange(2, maxnum):
        is_mul = False
        for prime in genPrimes():  # generate the primes from a file on disk
            if i % prime == 0:
                is_mul = True    
                break            
        if not is_mul:           
            addPrime(i)  # append the new prime to the end of your primes file

最后,您的硬盘上会有一个包含所有素数的文件。

好的,所以这会很慢,但你不会耗尽内存。您可以通过提高读取/写入文件的速度(例如RAID)来加快速度。