更新脚本中有错误。
我正在研究Julia&amp ;; Mandelbrot设置和Newton分形 - 为此我需要在复平面中计算很多的值。我可以使用我想要的任何类型的数学函数,但它足以用于多项式。
我需要计算函数/多项式的导数和值,所以我查看了numpy
模块,找到了关于numpy.polyder()
和numpy.polyval()
的信息。它看起来就像我需要的东西,但突然间我的脚本变得非常慢。
我试着想一些简单的测试来显示时间上的差异。为此我编写了以下脚本:
import numpy as np
import cmath
import time
from itertools import product
C = 0.37 + 0.45j
pol = [1,0,0]
start_time = time.time()
for i in xrange(100000):
C = np.polyval(pol, C)
print "Polyval: {}".format( time.time() - start_time )
print C
C = 0.37 + 0.45j # forgot to reassign the initial value of C
start_time = time.time()
for i in xrange(100000):
C = C**2
print "Standard: {}".format( time.time() - start_time )
print C
基本上这个脚本计算多项式g(C)= C ** 2的很多值。时间结果是(程序的实际输出):
Polyval: 2.34903216362
0j
Standard: 0.0198249816895
0j
我可能没有以最好的方式设置此测试,这是第一次做这样的事情。但即使出现任何错误,运行我的其他脚本也会显示出很大的差异。
有没有办法让它更快?我理解调用另一个函数是耗时的,但仍然。我是否应该重新考虑能够仅在一个地方改变多项式系数的优势,以及时间上的劣势?关于如何处理此类问题的任何其他建议?
答案 0 :(得分:2)
本身不是答案,但我写了一个函数polyval_factory
来生成一个mypolyval
函数给定一系列系数,如pol
。它以字符串形式生成快速表达式,如C*C + 1.0 * C *C*C + 2.0
,然后将它们装入lambda函数中。基本上它使用字符串代替完整的符号代数库,如sympy
。在下面的示例中定义并测试了此函数,其工作速度几乎与C*C
:
import numpy as np
import cmath
import time
from itertools import product
def polyval_factory(pol):
"""
Generate a lambda function for evaluating a given polynomial
pol : a list of coefficients with highest degree first
Note: this function basically uses strings in lieu of a
fully symbolic algebra package like sympy
"""
poly_string_list = []
for i, coeff in enumerate(pol[::-1]):
if np.abs(coeff) > 1e-10:
if i > 1:
poly_string_list.append( repr(coeff) + '*' + '*'.join(['x']*i))
elif i == 1:
poly_string_list.append(repr(coeff)+'*x')
elif i ==0:
poly_string_list.append(repr(coeff))
lambda_str = 'lambda x :' + '+'.join(poly_string_list)
print "The prepared lambda function is: \""+lambda_str + "\""
return eval(lambda_str)
C = 0.37 + 0.45j
pol = [1,0,0]
numiter = 30000
start_time = time.time()
for i in xrange(numiter):
C = np.polyval(pol, C)
print "Polyval: {}".format( time.time() - start_time )
print C
C = 0.37 + 0.45j # forgot to reassign the initial value of C
print ""
print "Generating lambda function..."
mypolyval = polyval_factory(pol) # generate the lambda function
print ""
start_time = time.time()
for i in xrange(numiter):
C = mypolyval(C)
print "Polyval_factory: {}".format( time.time() - start_time )
print C
C = 0.37 + 0.45j # forgot to reassign the initial value of C
print ""
start_time = time.time()
for i in xrange(numiter):
C = C**2
print "Standard: {}".format( time.time() - start_time )
print C
输出是:
Polyval: 0.738290071487
0j
Generating lambda function...
The prepared lambda function is: "lambda x :1*x*x"
Polyval_factory: 0.013610124588
0j
Standard: 0.00678110122681
0j
修改:polyval_factory
:现在正在运行mypolyval = polyval_factory([2.0,3.0,1.0])
做适当的事情并打印出来:
The prepared lambda function is: "lambda x :1.0+3.0*x+2.0*x*x"
答案 1 :(得分:2)
使用Horner方法时乘法顺序的奇怪性在速度上占约5倍。这在numpy 1.10中已修复,或者您可以使用已经修复的numpy.polynomial.polynomial.polyval
。有可能进一步矢量化,例如在numpy.polynomial.polynomial.polyval
版本中使用2d系数数组,但我不清楚你的要求是什么。另请注意,您可以直接将多项式迭代为p(p)
,但在某些时候我预计会导致数值问题。