我认为您不需要二项式展开。 Horner's method 用于评估多项式意味着多项式的因式分解比展开式更好。
一般来说,非线性方程求解可以从符号微分中受益,这对于您的方程而言并不难手动完成。为导数提供解析表达式可以使求解器不必对导数进行数值估计。您可以编写两个函数:一个返回函数的值,另一个返回导数(即这个简单一维函数的函数Jacobian),如the docs for scipy.optimize.fsolve() 中所述。一些采用这种方法的代码:
import timeit
import numpy as np
from scipy.optimize import fsolve
def the_function(x, y):
return y * (1 + x)**(4.8) / x**(4.5) - 1
def the_derivative(x, y):
l_dh = x**(4.5) * (4.8 * y * (1 + x)**(3.8))
h_dl = y * (1 + x)**(4.8) * 4.5 * x**3.5
square_of_whats_below = x**9
return (l_dh - h_dl)/square_of_whats_below
print fsolve(the_function, x0=1, args=(0.1,))
print '\n\n'
print fsolve(the_function, x0=1, args=(0.1,), fprime=the_derivative)
%timeit fsolve(the_function, x0=1, args=(0.1,))
%timeit fsolve(the_function, x0=1, args=(0.1,), fprime=the_derivative)
...给我这个输出:
[ 1.79308495]
[ 1.79308495]
10000 loops, best of 3: 105 µs per loop
10000 loops, best of 3: 136 µs per loop
这表明在这种特殊情况下,分析微分不会导致任何加速。我的猜测是,该函数的数值逼近涉及更易于计算的函数,例如乘法、平方和/或加法,而不是分数取幂之类的函数。
您可以通过记录方程的对数并绘制它来获得额外的简化。通过一点代数,您应该能够获得ln_y 的显式函数,即y 的自然对数。如果我正确地完成了代数:
def ln_y(x):
return 4.5 * np.log(x/(1.+x)) - 0.3 * np.log(1.+x)
你可以绘制这个函数,我已经为 lin-lin 和 log-log 绘制了这个函数:
%matplotlib inline
import matplotlib.pyplot as plt
x_axis = np.linspace(1, 100, num=2000)
f, ax = plt.subplots(1, 2, figsize=(8, 4))
ln_y_axis = ln_y(x_axis)
ax[0].plot(x_axis, np.exp(ln_y_axis)) # plotting y vs. x
ax[1].plot(np.log(x_axis), ln_y_axis) # plotting ln(y) vs. ln(x)
这表明只要y 低于临界值,每个y 就有两个x 值。 y 的最小奇异值出现在 x=ln(15) 和 y 值为:
np.exp(ln_y(15))
0.32556278053267873
因此,您的示例 y 的 1.03 值导致 x 没有(真正的)解决方案。
我们从情节中辨别出的这种行为被我们之前进行的scipy.optimize.fsolve() 调用所概括:
print fsolve(the_function, x0=1, args=(0.32556278053267873,), fprime=the_derivative)
[ 14.99999914]
这表明最初猜测x=1,当y 是0.32556278053267873 时,得到x=15 作为解决方案。尝试更大的y 值:
print fsolve(the_function, x0=15, args=(0.35,), fprime=the_derivative)
导致错误:
/Users/curt/anaconda/lib/python2.7/site-packages/IPython/kernel/__main__.py:5: RuntimeWarning: invalid value encountered in power
错误的原因是 Python(或 numpy)中的 power 函数默认情况下不接受小数指数的负基数。你可以通过提供复数的幂来解决这个问题,即写x**(4.5+0j)而不是x**4.5,但是你真的对可以解决你的方程的复杂x值感兴趣吗?