我正在研究这个快速的Eratosthenes发电机筛子,只是想知道为什么,如果检查'每个项目索引,代码运行速度比没有这个检查。谁会想到这个!?这是一般的使用技巧吗?
import time
def first(n):
s=time.time()
full_range = list(range(n))
zeroes = [0] * n
'''multiply n until sqrt(n)'''
for r in range(2, int(n**.5) + 1):
if full_range[r]: ##HERE##
full_range[2 * r:n:r] = zeroes[2 * r:n:r]
return list(filter(None, full_range)), print (time.time()-s)
def second(n):
s=time.time()
full_range = list(range(n))
zeroes = [0] * n
'''multiply n until sqrt(n)'''
for r in range(2, int(n**.5) + 1):
#if full_range[r]: ##HERE##
full_range[2 * r:n:r] = zeroes[2 * r:n:r]
return list(filter(None, full_range)), print (time.time()-s)
print(first(100000) == second(100000))
First 0.3749978542327881 seconds
Second 0.9687492847442627 seconds
True
答案 0 :(得分:0)
用语言来说,你正在做的过程说"将这个数字的所有倍数标记为零。" if
语句表示"仅当当前号码为素数时才执行下一步。"
对于筛子中的每个数字,第二个筛子必须将所有2的倍数,然后是3,然后是4,......第一个只将多个素数归零:2,然后是3,然后......
当它达到4时,它看到4已经归零。任何4的倍数也是2的倍数,因此它们已经归零。再次标记它们是浪费的工作。
现在我们做5,跳过6,做7,跳过8,9和10 ......
当我们只为主要的除数做这项工作时,我们节省了大量的工作。
答案 1 :(得分:0)
以此为例,说明为什么加速发生在这里:
def first(n):
s=time.time()
a = []
for r in range(n):
a += [r]
if r%2:
for i in range(r):
a[i] = i
return a, print (time.time()-s)
def second(n):
s=time.time()
a = []
for r in range(n):
a += [r]
for i in range(r):
a[i] = i
return a, print (time.time()-s)
>>> first(10000) == second(10000)
1.7188639640808105
3.406471014022827
True
通过添加if
语句,您可以摆脱最终不会影响代码结果的循环。通过不运行此循环(在您的情况下是扩展切片),您的程序可以在问题上花费更多时间,而不是花时间做一些对最终结果没有影响的事情。
修改强> 有趣的是,在运行您提供的代码时,我的时间非常相似,以至于您使用的代码并不重要(有时第一个比第二个慢):
>>> print(first(100000) == second(100000))
0.015606880187988281
0.015592098236083984
>>> print(first(100000) == second(100000))
0.015619993209838867
0.015625953674316406
>>> print(first(100000) == second(100000))
0.0
0.015592098236083984
>>> print(first(100000) == second(100000)) #something wrong with this one
0.0
0.03125309944152832
>>> print(first(100000) == second(100000))
0.0
0.0