我为Project Euler #5编写了这个解决方案。在
import time
start_time = time.time()
def ProjectEulerFive (m = 20):
a = m
start = 2
while (m % start) == 0:
start += 1
b = start
while b < m:
if ( a % b) != 0:
a += m
b = start
continue
else:
b += 1
return a
import sys
if (len(sys.argv)) > 2:
print "error: this function takes a max of 1 argument"
elif (len(sys.argv)) == 2:
print ProjectEulerFive(int(sys.argv[1]))
else:
print ProjectEulerFive();
print "took " + str(time.time() - start_time ) + " seconds"
我的系统需要8.5秒。在
然后我决定与其他人的解决方案进行比较。我找到这个了 Project Euler 5 in Python - How can I optimize my solution?。在
我没有想到唯一素数因式分解。在
但不管怎样,一个被认为是优化的基于非质数分解的解决方案张贴在那里:
^{pr2}$用我的系统大约37秒
我的代码大约快4倍,即使我不必要地检查3,4,5,6,7,8,9,10和12的整除性。在
我是python新手,很难看出效率低下的原因。在
编辑:
我又做了一个测试。在
import time
start_time = time.time()
def ProjectEulerFive (m = 20):
ls = [11, 13, 14, 15, 16, 17, 18, 19]
a = m
i = 0
while i < len(ls):
if ( a % ls[i]) != 0:
a += m
i = 0
continue
else:
i += 1
return a
print ProjectEulerFive();
print "took " + str(time.time() - start_time ) + " seconds"
我的系统需要6秒,但这:
import time
start_time = time.time()
def ProjectEulerFive (m = 20):
a = m
start = 11
b = start
while b < m:
if ( a % b) != 0:
a += m
b = start
continue
else:
b += 1
return a
print ProjectEulerFive()
print "took " + str(time.time() - start_time ) + " seconds"
大约需要3.7秒
这不需要花费时间:
我看到,虽然已经发布了一个更快的解决方案,但实际上没有人回答这个问题。事实上,这是一个很难回答的问题!基本的解释是函数调用相对昂贵。为了使这个结论具有说服力,我将不得不深入研究Python的内部结构。准备好了!在
首先,我将使用^{} 从“优化”解决方案中反汇编(您的第三个版本)}。这里有很多,但是快速扫描是确认代码根本不调用函数所需的全部内容:
ProjectEulerFive
和{现在让我们看看
^{pr2}$find_solution
:很快我们就明白了:(a)这段代码复杂得多,但(b)它还调用了三个不同的函数。第一个调用仅仅是对
xrange
的单个调用,但其他两个调用出现在最外层的for循环中。第一个调用是对all
的调用;我怀疑第二个调用是正在调用的生成器表达式的next
方法。但是函数是什么并不重要,重要的是它们在循环中被调用。在现在,你可能会想“有什么大不了的?”在这里。这只是一个函数调用;这里或那里几纳秒——对吗?但事实上,这些纳秒加起来。由于最外层的循环总共经过
232792560 / 20 == 11639628
个循环,因此任何开销都会乘以超过1100万个的。在ipython
中使用%timeit
命令的快速计时显示,在我的机器上,一个函数调用(全部是它本身)大约要花费120纳秒:因此,对于while循环中出现的每个函数调用,这将花费
120 nanoseconds * 11000000 = 1.32 seconds
更多的时间。如果第二个函数调用是对生成器表达式的next
方法的调用,那么该函数将被调用更多次,每次通过genex迭代一次——平均每个循环可能调用3-4次。在现在来验证这个假设。如果函数调用是问题所在,那么消除函数调用就是解决方法。让我们看看。。。在
这是
find_solution
的一个版本,它几乎与原始版本使用for/else
语法所做的完全相同。唯一的函数调用是外部调用xrange
,这应该不会引起任何问题。现在,当我计时原始版本时,花了11秒:让我们看看这个新的改进版管理了什么:
这比您在我的机器上最快版本的
ProjectEulerFive
的性能快一点:一切又有意义了。在
不是您问题的答案(因此有了community wiki),但下面是一个有用的计时函数修饰符:
用法如下:
^{pr2}$在实践中:
相关问题 更多 >
编程相关推荐