Trying to solve of Project Euler #10, but code takes *a lot* of time to display output
问题10:Project Euler
The sum of the primes below 10 is 2 + 3 + 5 + 7 = 17.
Find the sum of all the primes below two million.
我不认为有任何的代码中的错误。但这需要很多时间给我答案。我想使用它,因为我听到pypy更快比CPython的解释器,但仍然没有良好。
这里是代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | #Implementation of Sieve of Eratosthenes def prime_sieve(limit): primes = range(2, limit) for i in primes: for j in range(2, primes[-1]): try: primes.remove(i*j) except ValueError: pass return primes; answer = 0 for x in prime_sieve(2000000): answer += x print"Answer: %d." % answer raw_input() |
问题是:
1 | primes.remove(i*j) |
在大型列表上调用
这里还有其他方法可以更有效地使用数据结构(包括使用列表的其他方法和完全使用其他数据结构)。
最后:您的代码在对
下面是一个简单的易拉托斯坦筛子版本,它适合于计算和,而不是形成一个小于n的素数列表:
1 2 3 4 5 6 7 8 | def sumPrimes(n): sum, sieve = 0, [True] * n for p in range(2, n): if sieve[p]: sum += p for i in range(p*p, n, p): sieve[i] = False return sum |
有更好的方法来执行筛选,但是上面显示的函数对于这个项目欧拉问题是足够的;它应该在大约一秒钟内返回和。如果你对素数编程感兴趣,我会在我的博客上谨慎地推荐这篇文章。
基本筛选的正确数据结构是按整数值索引的位集。python没有内置的,但是由于您的限制很小(只有200万),所以一个常规的整数列表应该适合内存,即使它浪费了30倍或更多(在C中的等效位集需要250 kb的情况下,大约需要9 MB)。
对于速度来说,重要的是永远不要访问数组,除非通过立即直接索引(所以不要删除/删除)。此外,将筛子的外环限制为sqrt(极限),并将环前进到下一个质点,而不是下一个值。
所以类似这样的东西应该很快(在我的旧机器上用香草Python2.7大约需要2秒钟)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | import math, sys def prime_sieve(limit): # Mark everything prime to start primes = [1 for x in xrange(limit)] primes[0] = 0 primes[1] = 0 # Only need to sieve up to sqrt(limit) imax = int(math.sqrt(limit) + 1) i = 2 while (i < imax): j = i + i while j < limit: primes[j] = 0 j += i # Move i to next prime while True: i += 1 if primes[i] == 1: break return primes s = prime_sieve(2000000) print(sum(i for i in xrange(len(s)) if s[i] == 1)) |
一个更有效的想法是这样的:
从列表开始:
1 | [0,1,2,3,4,5,6,7,8,9,10] |
要将非素数的每个元素设置为0,并保留素数。
将0和1设置为0,因为它们不是素数。从现在开始你需要做这两件事步骤:
1)找出你还没有考虑过的最小素数,我们称之为n。
2)将每个第n个元素设置为0(但不是n),因为它们是n的倍数
例如:将0和1设置为0之后:
1 | [0,0,2,3,4,5,6,7,8,9,10] |
你没有考虑过的最小素数是2,所以你把每秒钟的元素都设置为0(但不是2):
1 | [0,0,2,3,0,5,0,7,0,9,0] |
你没有考虑过的最小素数是3,所以你把每三个元素都设为0(但不是3),依此类推……
1 | [0,0,2,3,0,5,0,7,0,0,0] |
另外要注意的是,你不必为每一个素数都这样做,一旦素数达到sqrt(极限),你就可以停止,因为你知道所有非素数都被设置为零。
例如,10的平方根(在本例中是极限)是3.162,这意味着当我们达到5时,我们不需要做任何事情,我们在那一点上完成了。但为什么呢?我们使用每个素数将其倍数设置为零,因为这些倍数不是素数;但是,由于5大于10的平方根,5的任何倍数必须是小于5的数字的倍数,因此已经设置为0。
假设我们的初始范围是从20到20。20的平方根小于5,所以我们不需要检查5,因为5的所有倍数:5*2=10,5*3=15,5*2*2=20都是较小素数的倍数,我们已经将它们设置为0。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | def isPrime(n): if n < 2: return"Neither prime, nor composite" for i in range(2, int(n**0.5) + 1): if n % i == 0: return False return True def sumPrime(): sumT = 0 for i in range(2,2000000): if(isPrime(i)): sumT = sumT + i return sumT |