Euler#10项目(Python)
为什么我计算所有素数之和小于200万的算法这么慢? 我是一个相当初级的程序员,这就是我为找到解决方案而想到的:Euler#10项目(Python),python,python-2.7,Python,Python 2.7,为什么我计算所有素数之和小于200万的算法这么慢? 我是一个相当初级的程序员,这就是我为找到解决方案而想到的: import time sum = 2 start = time.time() for number in range(3, 2000000): prime = True for x in range(2, number): if number % x == 0: prime = False if prime:
import time
sum = 2
start = time.time()
for number in range(3, 2000000):
prime = True
for x in range(2, number):
if number % x == 0:
prime = False
if prime:
sum += number
print "Sum =", sum
end = time.time() - start
print "Runtime =", end
有人能帮我吗?
谢谢 首先,你循环了太多的数字。你不需要检查每一个小于一个给定数的数是否是一个除数来检查一个数是否是素数(我会让你自己弄清楚这是为什么)。您正在运行数千亿个循环,其中有数亿个循环可以运行 类似的方法工作得更快,但决不是最佳的:
value=2
for i in range(3, 2000000):
prime=True
if i%2 != 0:
for j in range(3, int(round(sqrt(i)+1)),2):
if i % j==0:
prime=False
else:
prime=False
if prime==True:
value+=i
print value
您可以做很多优化(而且应该做,因为project Euler中的许多问题都需要原始生成,所以快速实现可以简化以后的工作) 看看Atkin的筛子(和相关的筛子)(),了解如何通过蛮力(即算法)加速素代
然后看看这篇S.O.-post()的绝妙答案,它记录了许多素数生成算法/实现。您需要使用素数筛检查eratostheneses筛并尝试在代码中实现它
试除法在寻找素数时效率很低,因为它具有复杂度n平方,运行时间增长很快。此任务旨在教您如何找到更好的方法。没有人指出这一点,但在Python2.x中使用
range
非常缓慢。使用xrange
instaed,在这种情况下,这将给您带来巨大的性能优势。看
此外,在检查数字之前不必循环,检查直到
round(sqrt(n))+1
就足够了。(如果大于其平方的数字除以它,那么肯定有一个小于你已经注意到的平方的数字。)你的算法使用的是试除法,速度非常慢。一种更好的算法是使用埃拉托斯坦筛:
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
print sumPrimes(2000000)
这应该在不到一秒钟的时间内完成。如果你对素数编程感兴趣,我在我的博客上谦虚地推荐这个问题。当你使用eratosthenes筛时,这个问题的输出速度非常快。只需稍加修改,就可以使它更快,比如只考虑奇数,只需将整个200万个数字迭代一半。这样你可以节省很多时间
n = 2000000
ar = [False for x in range(n)]
sum = 2
def mul(a):
i = 2;p = i*a
while (p < n):
ar[p] = 1
++i
p = i*a
while (x < n):
if(ar[x] == 0):
sum += x;mul(x)
x += 2
print (sum)
n=2000000
ar=[范围(n)内x为假]
总和=2
def mul(a):
i=2;p=i*a
而(p
在这里,您可以在c++中看到相同的算法:-
#include<bits/stdc++.h>
using namespace std;
const int n = 2000000;
bool ar[n];
void mul(int a)
{
int i = 2;int p = i*a;
while(p < n)
{
ar[p] = 1;
++i;p = i*a;
}
}
long long sieve()
{
long long sum = 2;
for(int i = 3;i < n;i += 2)
{
if(ar[i] == 0)
sum += i,mul(i);
}
return sum;
}
int main()
{
cout<<sieve();
return 0;
}
#包括
使用名称空间std;
常数int n=2000000;
布尔ar[n];
无效mul(内部a)
{
int i=2;int p=i*a;
而(psum=2
def iPrime(n):
如果n%2==0:返回False
对于范围(3,int(n**0.5)+1,2)内的i:
如果n%i==0:返回False
返回真值
如果名称=“\uuuuu main\uuuuuuuu”:
n=1
当n<2000000时:
n+=2
如果isPrime(n):总和+=n
打印金额
首先,我认为您可以通过定义函数来拆分代码。但是,在这种情况下,使用常规函数有一个缺点,因为每次普通函数返回值时,对该函数的下一次调用都会再次执行函数内的完整代码。由于您迭代了200万次,因此最好是:
- 具有一个函数,该函数为您提供下一个素数,并将控件临时返回给调用者。此类函数称为
- 要定义生成器函数,只需使用
yield
命令,而不是return
- 当您使用生成器时,就像知道函数将再次被调用一样,当调用发生时,函数内部的执行将在
yield
指令之后继续,而不是再次检查整个函数
- 这种方法的优点是,在迭代器的长期运行中,可以避免消耗系统的所有内存
我建议您看看。它为这个例子提供了更广泛的解释
解决方案如下:
import math
# Check if a number is prime
def is_prime(number):
if number > 1:
if number == 2:
return True
if number % 2 == 0:
return False
for current in range(3, int(math.sqrt(number) + 1), 2):
if number % current == 0:
return False
return True
return False
# Get the next after a given number
def get_primes(number):
while True:
if is_prime(number):
yield number
# Next call to the function will continue here!
number += 1
# Get the sum of all prime numbers under a number
def sum_primes_under(limit):
total = 2
for next_prime in get_primes(3):
if next_prime < limit:
total += next_prime
else:
print(total)
return
# Call the function
sum_primes_under(2000000)
导入数学
#检查一个数字是否为素数
def是_素数(数字):
如果数字>1:
如果数字==2:
返回真值
如果数字%2==0:
返回错误
对于范围内的电流(3,int(数学sqrt(数字)+1),2):
如果编号%current==0:
返回错误
返回真值
返回错误
#在给定的数字之后获取下一个
def get_素数(数量):
尽管如此:
如果是素数(数字):
产量
#对函数的下一次调用将在此处继续!
数字+=1
#求一个数下所有素数的和
def sum_primes_低于(限制):
总数=2
对于get_素数(3)中的下一个_素数:
如果下一个_素数<极限:
总数+=下一个素数
其他:
打印(总计)
返回
#调用函数
总素数低于(2000000)
因为你循环了200万次,超过了两次。请尝试先过滤掉它,这样你就只循环了素数(提示,首先只从奇数开始)在eratostheneses和一个一个算法的优化方法之间得到了一个x140因子。我是一个初学者,但我仍然不理解你们的代码。这意味着什么?ar=[False代表范围内的x(n)]
我还运行了你的代码,它说你在赋值之前引用了局部变量x
。这是什么意思?sum,sieve=0,[True]*n
我是编程新手,所以可以
import math
# Check if a number is prime
def is_prime(number):
if number > 1:
if number == 2:
return True
if number % 2 == 0:
return False
for current in range(3, int(math.sqrt(number) + 1), 2):
if number % current == 0:
return False
return True
return False
# Get the next after a given number
def get_primes(number):
while True:
if is_prime(number):
yield number
# Next call to the function will continue here!
number += 1
# Get the sum of all prime numbers under a number
def sum_primes_under(limit):
total = 2
for next_prime in get_primes(3):
if next_prime < limit:
total += next_prime
else:
print(total)
return
# Call the function
sum_primes_under(2000000)
import time
start = time.time()
def is_prime(num):
prime = True
for i in range(2,int(num**0.5)+1):
if num % i == 0:
prime = False
break
return prime
sum_prime = 0
for i in range(2,2000000):
if is_prime(i):
sum_prime += i
print("sum: ",sum_prime)
elapsed = (time.time() - start)
print("This code took: " + str(elapsed) + " seconds")