2013-04-18 24 views
8

Tôi hiện đang làm việc thông qua các vấn đề về Dự án Euler, và cho đến nay tôi đã đưa ra mã này cho một vấn đề.Có cách nào để tránh lỗi bộ nhớ này không?

from itertools import combinations 
import time 

def findanums(n): 
    l = [] 
    for i in range(1, n + 1): 
     s = [] 
     for j in range(1, i): 
      if i % j == 0: 
       s.append(j) 
     if sum(s) > i: 
      l.append(i) 
    return l 

start = time.time() #start time 

limit = 28123 

anums = findanums(limit + 1) #abundant numbers (1..limit) 
print "done finding abundants", time.time() - start 

pairs = combinations(anums, 2) 
print "done finding combinations", time.time() - start 

sums = map(lambda x: x[0]+x[1], pairs) 
print "done finding all possible sums", time.time() - start 

print "start main loop" 
answer = 0 
for i in range(1,limit+1): 
    if i not in sums: 
     answer += i 
print "ANSWER:",answer 

Khi tôi chạy điều này, tôi chạy vào MemoryError.

Các traceback:

File "test.py", line 20, in <module> 
    sums = map(lambda x: x[0]+x[1], pairs) 

tôi đã cố gắng để ngăn chặn nó bằng cách tắt thu gom rác thải từ những gì tôi đã có thể nhận được từ Google nhưng không có kết quả. Tôi đang tiếp cận điều này một cách sai lầm? Trong đầu tôi, cảm giác này giống như cách tự nhiên nhất để làm điều đó và tôi đang thua lỗ vào thời điểm này.

SIDE LƯU Ý: Tôi đang sử dụng PyPy 2.0 Beta2 (Python 2.7.4) vì nó nhanh hơn rất nhiều so với bất kỳ triển khai python nào khác mà tôi đã sử dụng và Scipy/Numpy trên đầu vì tôi vẫn chỉ bắt đầu chương trình và tôi không có nền tảng kỹ thuật hoặc toán học mạnh mẽ.

+0

Bạn nhận được bao nhiêu bộ nhớ? hệ thống 64-bit là gì? – Ofiris

+0

64 bit, 8 GB bộ nhớ, mặc dù PyPy là 32 bit nếu điều đó tạo ra sự khác biệt. –

+2

Dường như bạn có lỗi ở đâu đó. Nếu bạn 'in len (anums)' sau khi 'findanums' chạy, nó cho' 28123', có nghĩa là số _every_ từ một đến 28123 là một số phong phú. Tôi không nghĩ điều đó đúng. – Kevin

Trả lời

4

Như Kevin đề cập trong nhận xét, thuật toán của bạn có thể sai, nhưng dù sao mã của bạn không được tối ưu hóa.

Khi sử dụng danh sách rất lớn, người ta thường sử dụng generators, có một, câu trả lời Stackoverflow lớn nổi tiếng giải thích các khái niệm về yieldgenerator-What does the "yield" keyword do in Python?

Vấn đề là bạn pairs = combinations(anums, 2) không tạo ra một generator , nhưng tạo ra một vật thể lớn tiêu thụ nhiều bộ nhớ hơn.

tôi đã thay đổi mã của bạn để có chức năng này, vì bạn lặp lại trong bộ sưu tập lần duy nhất, bạn có thể lười biếng đánh giá các giá trị:

def generator_sol(anums1, s): 
     for comb in itertools.combinations(anums1, s): 
     yield comb 

Bây giờ thay vì pairs = combinations(anums, 2) mà tạo ra một đối tượng lớn. Sử dụng:

pairs = generator_sol(anums, 2) 

Sau đó, thay vì sử dụng lambda tôi sẽ sử dụng một generator:

sums_sol = (x[0]+x[1] for x in pairs) 

Một mẹo, bạn nhìn tốt hơn ở xrange đó là phù hợp hơn, nó doens't tạo ra một danh sách nhưng xrange object hiệu quả hơn trong nhiều trường hợp (chẳng hạn như ở đây).

+0

Bây giờ, nó chỉ phát ra một câu trả lời sai. Bạn đã cho tôi rất nhiều điều để đọc và học hỏi để tôi cảm ơn bạn. Máy phát điện đã thực sự giải quyết vấn đề bộ nhớ của tôi! –

+2

Chúc may mắn với Project Euler. – Ofiris

+2

phạm vi không tạo ra một danh sách trong pypy hoặc – fijal

1

Vấn đề là anums là lớn - khoảng 28000 phần tử dài. các cặp phải là 28000 * 28000 * 8 byte = 6 GB. Nếu bạn sử dụng NumPy bạn có thể cast anums như một mảng numpy.int16, trong trường hợp các cặp kết quả sẽ là 1.5GB - dễ quản lý hơn:

import numpy as np 
#cast 
anums = np.array([anums],dtype=np.int16) 
#compute the sum of all the pairs via outer product 
pairs = (anums + anums.T).ravel() 
+1

Như tôi đã nói trong bài đăng của tôi, tôi vẫn còn khá xanh và ma thuật của numpy vẫn còn trong tầm tay của tôi tại thời điểm này như tôi vẫn đang học các thư viện Python bình thường . Nhưng tôi đánh giá cao câu trả lời này dù sao nó mang lại cho tôi một hương vị của những gì tôi có thể làm một khi tôi học đủ để sử dụng numpy/scipy! –

2

Hãy để tôi đề nghị bạn sử dụng generators. Hãy thử thay đổi này:

sums = map(lambda x: x[0]+x[1], pairs) 

để

sums = (a+b for (a,b) in pairs) 

giải pháp Ofiris cũng ok nhưng ngụ ý rằng itertools.combinations trả về một danh sách khi nó sai. Nếu bạn tiếp tục giải quyết các vấn đề về dự án euler, hãy xem itertools documentation.

+1

Nhận xét hay, cảm ơn, Đã sửa lỗi. – Ofiris

+0

Bạn có ý gì khi 'kết hợp' trả về một danh sách khi nó sai? –

+1

Tôi đã nói kết hợp trả về một 'danh sách' và nó không chính xác, cố định nó dù sao đi nữa. – Ofiris

Các vấn đề liên quan