我正在尝试在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
答案 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)
这是一个更复杂的算法,也许在技术上不算作筛子,但一种方法是不立即删除给定素数的所有倍数,而是排队下一个倍数(连同素数)。这可以用在生成器实现中。队列仍然会包含很多(多个)素数,但不会像构建然后过滤列表那样多。
手动完成前几个步骤,以显示原则......
注意 - 队列不是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)来加快速度。