用python实现素数
我对编程相当陌生,我决定做一些练习来提高我的能力。我一直在做一个练习:“找出200万以下所有素数的总和。”我的代码太慢了 起初,我试图作为一个普通的素数问题来解决,结果是:用python实现素数,python,performance,loops,primes,Python,Performance,Loops,Primes,我对编程相当陌生,我决定做一些练习来提高我的能力。我一直在做一个练习:“找出200万以下所有素数的总和。”我的代码太慢了 起初,我试图作为一个普通的素数问题来解决,结果是: sum = 2 + 3 for i in range (5, 2000000, 2): for j in range (3, i, 2): if i%j == 0: break else: sum += i print(sum) 这样,所有偶数都将从循
sum = 2 + 3
for i in range (5, 2000000, 2):
for j in range (3, i, 2):
if i%j == 0:
break
else:
sum += i
print(sum)
这样,所有偶数都将从循环中排除。但这并没有解决我的问题。这里的震级真的很大
所以我试图理解这段代码发生了什么。我在循环中有一个循环,循环中的循环运行外部循环时间的索引(不完全是这样,因为列表不是从0开始的),对吗?所以,当我试图找到20以下的素数时,它运行外部循环8次,但内部循环60次(我不知道这个数学是否正确,正如我所说,我对编程非常熟悉)。但是当我使用2000000的时候,我总共运行了大约999930012次内部循环,这太疯狂了
我的朋友告诉我关于埃拉托什尼筛的事,我试图创建一个新的代码:
list = [2]
list.extend(range(3, 2000000, 2))
for i in list:
for j in list:
if j%i == 0 and j > i:
list.remove(j)
print(sum(list))
这就是我尝试模拟筛子的结果(忽略偶数有帮助)。它的速度要快得多(使用其他代码,要找到200000以下的素数需要很长时间,使用这个新代码我可以做到),但它不足以在合理的时间内计算2000000000。自从我开始编写代码以来,代码一直在后台运行,但仍然没有任何内容。我不知道这东西循环了多少次,我现在想都想不起来了
我是来寻求帮助的。为什么这么慢?我应该学习/阅读/做些什么来改进我的代码?还有比这个筛子更有效的方法吗?谢谢您抽出时间。因为
list.remove
是一个O(n)
操作,您做了很多。你不是在做一个真正的筛子,只是在伪装中进行试飞;您仍在执行在原始代码中执行的所有剩余测试
Eratosthenes筛通常使用一组标志来实现;在最简单的形式中,每个索引对应于相同的数字,并且除了
0
和1
之外,所有索引的值最初都是True
。迭代,当您找到一个True
值时,您可以将其倍数的所有索引设置为False
。这意味着工作是顺序加法,而不是乘法,而不是除法(这要昂贵得多)。你能再解释一下吗?好的,涵盖第一个筛选情况。当你迭代时,你会发现索引2是真的(素数)。此时,您知道2的所有倍数在定义上都不是素数。因此,您可以只从2*2
循环到2000000
,通过2
(例如,使用范围(p*p,len(标志),p)
),并将标志列表中的条目设置为False
。不需要大内存移动(甚至不检查不是倍数的标志),不进行乘法或余数测试(并且xrange
/range
的加法速度更快).3
是同一笔交易;该标志仍然为true,因此它是prime,您可以将所有标志从3*3
设置为2000000
逐步从3
设置为False
(实际上,作为一种优化,除了2
之外,对于3
,您可以逐步使用2*p
,或者6
,因为偶数值肯定不是素数)。@settifoglio:如果您想要示例,它们不是超优化的(“数组”)通过巧妙地使用bytearray
),基于字节的版本在速度和性能上都可以得到极大的提高,但它们在算法上明显优于现有版本,应该足以筛选出前2M个素数(使用超优化的代码,您可以轻松地将工作量减少10倍或更多,但在这里只需一两秒钟并不重要)。谢谢您,先生。我一定会尝试您的建议和Rosetta。您所说的非常有意义,非常感谢。