处理python中大计算的内存使用情况

时间:2011-08-27 19:27:05

标签: python stack-overflow sieve-of-eratosthenes prime-factoring

我正在尝试用python进行一些计算,我的内存不足。因此,我想读/写一个文件以释放内存。我需要一个像一个非常大的列表对象的东西,所以我想为文件中的每个对象写一行,并读取/写入那些行而不是内存。行排序对我很重要,因为我将使用行号作为索引。所以我想知道如何在python中替换线条而不移动其他线条(实际上,移动线条是好的,只要它们返回到我期望它们的位置)。

修改

我正在尝试帮助一个朋友,这个朋友在python中差于或等于我。这段代码应该找到最大的素数,它除以给定的非素数。这个代码适用于数字,直到100万这样的数字,但是在死后,我的记忆在尝试制作数字列表时会耗尽。

# a comes from a user input
primes_upper_limit = (a+1) / 2
counter = 3L
numbers = list()
while counter <= primes_upper_limit:
    numbers.append(counter)
    counter += 2L

counter=3
i=0
half = (primes_upper_limit + 1) / 2 - 1
root = primes_upper_limit ** 0.5
while counter < root:
    if numbers[i]:
        j = int((counter*counter - 3) / 2)
        numbers[j] = 0
        while j < half:
            numbers[j] = 0
            j += counter
    i += 1
    counter = 2*i + 3
primes = [2] + [num for num in numbers if num]
for numb in reversed(primes):
    if a % numb == 0:
        print numb
        break
另一个编辑

如何为每个索引编写不同的文件?例如,十亿个带有长整数文件名的文件,只是文件中的一个数字?

4 个答案:

答案 0 :(得分:2)

你想找到一个最大的素数除数。 (Project Euler Question 3) 您当前选择的算法和实现方法是:

  1. 生成范围内所有候选素数的列表numbers(3&lt; = n&lt; = sqrt(a),或(a + 1)/ 2),正如您目前所做的那样)
  2. 筛选numbers列表以获取素数列表{p}&lt; = sqrt(a)
  3. 试验部:按每个p测试a的可分性。存储a。
  4. 的所有素数除数{q}
  5. 打印所有除数{q};我们只想要最大的。
  6. 我对此算法的评论如下。正如欧文和我所评论的那样,筛分和试验分区是严重不可扩展的算法。对于大的(十亿或万亿)你真的应该使用NumPy。无论如何,有关实施此算法的一些意见:

    1. 你知道吗你只需要测试√aint(math.sqrt(a)),而不是(a + 1)/ 2吗?
    2. 没有必要建立一个庞大的候选人名单numbers ,然后筛选它的优势 - 数字列表不可扩展。只需直接构建列表primes 。你可以使用while / for-loops和xrange(3,sqrt(a)+2,2)(它给你一个迭代器)。正如你在2**31L提到xrange()溢出,但结合sqrt观察,你仍然可以成功地将因子考虑到2**62
    3. 一般来说,这不如得到a的素数分解,即每次找到素数除数p | a,你只需要继续筛选剩余因子a / p或a /p²或a /p³或其他)。除了罕见的非常大的素数(或伪极数),这将大大减少你正在使用的数字的大小。
    4. 此外,您只需要生成素数列表{p}一次;然后存储它并进行查找,而不是重新生成它。 所以我会将generate_primes(a)find_largest_prime_divisor(a)区分开来。分解有很大帮助。
    5. 这是我对您的代码的重写,但由于保留了筛选列表,性能仍然在数十亿(a> 10 ** 11 +1)中下降。我们可以使用collections.deque代替素数列表来获得更快的O(1)append()操作,但这是一个小的优化。

      # Prime Factorization by trial division
      
      from math import ceil,sqrt
      from collections import deque
      
      # Global list of primes (strictly we should use a class variable not a global)
      #primes = deque()
      primes = []
      
      def is_prime(n):
          """Test whether n is divisible by any prime known so far"""
          global primes
          for p in primes:
               if n%p == 0:
                   return False #  n was divisible by p
          return True # either n is prime, or divisible by some p larger than our list    
      def generate_primes(a):
          """Generate sieved list of primes (up to sqrt(a)) as we go"""
          global primes
          primes_upper_limit = int(sqrt(a))
          # We get huge speedup by using xrange() instead of range(), so we have to seed the list with 2
          primes.append(2)
          print "Generating sieved list of primes up to", primes_upper_limit, "...",
          # Consider prime candidates 2,3,5,7... in increasing increments of 2
          #for number in [2] + range(3,primes_upper_limit+2,2):
          for number in xrange(3,primes_upper_limit+2,2):
              if is_prime(number): # use global 'primes'
                  #print "Found new prime", number
                  primes.append(number) # Found a new prime larger than our list
          print "done"    
      def find_largest_prime_factor(x, debug=False):
          """Find all prime factors of x, and return the largest."""
          global primes
          # First we need the list of all primes <= sqrt(x)    
          generate_primes(x)
          to_factor = x # running value of the remaining quantity we need to factor
          largest_prime_factor = None
          for p in primes:
              if debug: print "Testing divisibility by", p
              if to_factor%p != 0:
                  continue
              if debug: print "...yes it is"
              largest_prime_factor = p
              # Divide out all factors of p in x (may have multiplicity)
              while to_factor%p == 0:
                  to_factor /= p
              # Stop when all factors have been found
              if to_factor==1:
                  break
          else:
              print "Tested all primes up to sqrt(a), remaining factor must be a single prime > sqrt(a) :", to_factor
          print "\nLargest prime factor of x is", largest_prime_factor
          return largest_prime_factor
      

答案 1 :(得分:0)

如果我理解正确,这不是一件容易的事。他们解释它的方式,你想保持文件句柄打开,并使用该文件作为存储字符数据的地方。

假设您有一个像

这样的文件
a
b
c

你想用'bb'替换'b'。这将是一个痛苦,因为文件实际上看起来像a\nb\nc - 你不能只覆盖b,你需要另一个字节。

我的建议是尝试找到一种方法,使您的算法无需使用文件即可进行额外存储。如果你有一个堆栈溢出,你可能没有真正耗尽内存,你超越了调用堆栈, 更小。

您可以尝试将算法重新编写为不递归。有时您可以使用list替换调用堆栈 - 但是您可以做很多事情,我认为我不会给出很多一般性建议而不会看到您的算法。

修改

啊,我明白你的意思......当列表

while counter <= primes_upper_limit:
    numbers.append(counter)
    counter += 2L

变得非常大,你可能会耗尽内存。所以我猜你基本上都在筛选,这就是为什么你有大名单numbers?这说得通。如果你想继续这样做,你可以尝试一个numpy bool数组,因为它将每个单元使用更少的内存:

import numpy as np

numbers = np.repeat(True, a/2)

或者(也许这并不吸引人)你可以采用一种完全不同的方法,不使用大清单,例如完全分解数字并选择最大因素。

类似的东西:

factors = [ ]
tail = a

while tail > 1:
    j = 2
    while 1:
        if tail % j == 0:
            factors.append(j)
            tail = tail / j
            print('%s %s' % (factors, tail))
            break
        else:
            j += 1

即说你要考虑因素20tail20开头,然后你发现2 tail变为10,然后它变为5

对于大型(数十亿)素数而言,效率并不高,并且方式太慢,但对于具有小因子的数字,它可以。

我的意思是你的筛子也很好,直到你开始耗尽记忆力;)。你可以给numpy一个镜头。

答案 2 :(得分:0)

pytables非常适合处理和存储大量数据。但首先要在smci的答案中实施评论,以尽量减少您需要存储的数字量。

答案 3 :(得分:0)

对于只有12位数的数字,如Project Euler#3,不需要花哨的整数分解方法,也不需要在磁盘上存储中间结果。使用此算法查找n:

的因子
  1. 设置f = 2。
  2. 如果n = 1,请停止。
  3. 如果f * f> n,打印n并停止。
  4. 将n除以f,同时保持商q和余数r。
  5. 如果r = 0,则打印q,将n除以q,然后转到步骤2.
  6. 否则,将f增加1并转到步骤3.
  7. 这只是按每个整数进行试验除法,直到达到平方根,这表明剩余的辅因子是素数。每个因素都会在找到时打印出来。