牛顿#
- scipy.optimize.newton(func, x0, fprime=None, args=(), tol=1.48e-08, maxiter=50, fprime2=None, x1=None, rtol=0.0, full_output=False, disp=True)[源代码][源代码]#
使用牛顿-拉夫森(或割线法或哈雷法)方法求解实数或复数函数的根。
找到标量值函数 func 在给定邻近标量起点 x0 处的根。如果提供了 func 的导数 fprime,则使用牛顿-拉夫森方法;否则使用割线法。如果还提供了 func 的二阶导数 fprime2,则使用哈雷方法。
如果 x0 是一个包含多个元素的序列,
newton
返回一个数组:从 x0 中每个(标量)起始点开始,函数的根。在这种情况下,func 必须被向量化,以返回与其第一个参数相同形状的序列或数组。如果提供了 fprime`(或 `fprime2),那么它的返回值也必须具有相同的形状:每个元素是 func 对其唯一变量的第一(第二)导数,在第一个参数的每个元素处求值。newton
用于寻找单变量标量值函数的根。对于涉及多个变量的问题,请参见root
。- 参数:
- 函数可调用
想要找到其根的函数。它必须是一个单变量的函数,形式为
f(x,a,b,c...)
,其中a,b,c...
是可以在 args 参数中传递的额外参数。- x0浮点数, 序列, 或 ndarray
一个初始的根估计值,应该接近实际的根。如果不是标量,那么 func 必须向量化,并返回与其第一个参数形状相同的序列或数组。
- fprime可调用,可选
当函数导数可用且方便时。如果为 None(默认),则使用割线法。
- 参数tuple, 可选
在函数调用中使用的额外参数。
- tolfloat, 可选
根值的允许误差。如果 func 是复数值,建议使用较大的 tol,因为 x 的实部和虚部都会对
|x - x0|
产生贡献。- maxiterint, 可选
最大迭代次数。
- fprime2可调用,可选
当函数的二阶导数可用且方便时。如果为 None(默认),则使用普通的牛顿-拉弗森法或割线法。如果不为 None,则使用哈雷法。
- x1float, 可选
另一个估计的根,应该在实际根的附近。如果未提供 fprime ,则使用此估计。
- rtolfloat, 可选
终止的容差(相对)。
- 完整输出bool, 可选
如果 full_output 为 False(默认),则返回根。如果为 True 且 x0 是标量,返回值为
(x, r)
,其中x
是根,r
是一个RootResults
对象。如果为 True 且 x0 是非标量,返回值为 ``(x, converged, zero_der)``(详见返回部分)。- dispbool, 可选
如果为 True,则在算法未收敛时引发 RuntimeError,错误消息包含迭代次数和当前函数值。否则,收敛状态记录在
RootResults
返回对象中。如果 x0 不是标量,则忽略此参数。注意:这与显示无关,但由于向后兼容性,`disp` 关键字不能重命名。
- 返回:
- 根浮点数, 序列, 或 ndarray
函数为零的估计位置。
- r :
RootResults
, 可选RootResults,可选 如果
full_output=True
且 x0 是标量,则存在。包含有关收敛信息的对象。特别是,如果例程收敛,则r.converged
为 True。- 收敛布尔值的 ndarray,可选
如果
full_output=True
且 x0 为非标量,则存在。对于向量函数,指示哪些元素成功收敛。- zero_der布尔值的 ndarray,可选
如果
full_output=True
且 x0 是非标量,则存在。对于向量函数,指示哪些元素具有零导数。
参见
root_scalar
标量函数根求解器的接口
root
多输入、多输出函数的根求解器接口
注释
牛顿-拉夫森方法的收敛速度是二次的,Halley方法是三次的,而割线方法是次二次的。这意味着如果函数表现良好,第n次迭代后的实际误差大约是第(n-1)步误差的平方(对于Halley方法则是立方)。然而,这里使用的停止准则是步长,并不能保证已经找到根。因此,结果应进行验证。更安全的算法是brentq、brenth、ridder和bisect,但它们都要求根首先被夹在函数改变符号的区间内。当找到这样的区间时,brentq算法推荐用于一维问题的一般使用。
当
newton
与数组一起使用时,它最适合以下类型的问题:初始猜测值 x0 都相对地与根的距离相同。
一些或所有的额外参数,args,也是数组,以便可以一起解决一类相似的问题。
初始猜测值 x0 的大小超过 O(100) 个元素。否则,一个简单的循环可能表现得和向量化一样好,甚至更好。
示例
>>> import numpy as np >>> import matplotlib.pyplot as plt >>> from scipy import optimize
>>> def f(x): ... return (x**3 - 1) # only one real root at x = 1
fprime
未提供,使用割线法:>>> root = optimize.newton(f, 1.5) >>> root 1.0000000000000016 >>> root = optimize.newton(f, 1.5, fprime2=lambda x: 6 * x) >>> root 1.0000000000000016
仅提供
fprime
,使用牛顿-拉夫森方法:>>> root = optimize.newton(f, 1.5, fprime=lambda x: 3 * x**2) >>> root 1.0
提供了
fprime2
和fprime
,使用 Halley 方法:>>> root = optimize.newton(f, 1.5, fprime=lambda x: 3 * x**2, ... fprime2=lambda x: 6 * x) >>> root 1.0
当我们想要为一组相关的初始值和/或函数参数找到根时,我们可以将这两者作为输入数组提供:
>>> f = lambda x, a: x**3 - a >>> fder = lambda x, a: 3 * x**2 >>> rng = np.random.default_rng() >>> x = rng.standard_normal(100) >>> a = np.arange(-50, 50) >>> vec_res = optimize.newton(f, x, fprime=fder, args=(a, ), maxiter=200)
上述等同于在for循环中分别求解
(x, a)
中的每个值,只是速度更快:>>> loop_res = [optimize.newton(f, x0, fprime=fder, args=(a0,), ... maxiter=200) ... for x0, a0 in zip(x, a)] >>> np.allclose(vec_res, loop_res) True
绘制所有
a
值的结果:>>> analytical_result = np.sign(a) * np.abs(a)**(1/3) >>> fig, ax = plt.subplots() >>> ax.plot(a, analytical_result, 'o') >>> ax.plot(a, vec_res, '.') >>> ax.set_xlabel('$a$') >>> ax.set_ylabel('$x$ where $f(x, a)=0$') >>> plt.show()