果然不愧是牛顿发明的东西,是真的很有用。
简介
牛顿迭代法通常用于寻找方程
f(x)=0 的根的迭代算法,从猜测值开始不断逼近,迭代次数通常自己决定。显然地,如果你迭代的次数越多,你的结果就越精确。
公式
我们记初始的猜测值为
x0,之后第
n 次迭代的结果为
xn。
考虑计算在点
xn 处的一阶泰勒展开,有:
f(x)≈f(xn)+f′(xn)(x−xn)
令
f(x)=0,我们开心地发现了这个结论:
xn+1=xn−f′(xn)f(xn)
欸,这不就可以一直迭代近似了吗?这正是牛顿迭代的公式。
收敛证明
请注意收敛证明仍然是不可或缺的一部分。
设有函数
f(x),且
f 在根
r 附近二次连续可微,也即存在
f(x) 的二阶导,并且
f′(r)=0,也即单根。
注意到泰勒展开:
0=f(r)=f(xn)+f′(xn)(r−xn)+2f′′(ξ)(r−xn)2
整理,可以得到:
xn−f′(xn)f(xn)−r=xn+1−r=2f′(xn)f′′(ξ)(xn−r)2
换元(或者不换,这里就不换了),可以得到它是平方收敛的。
例题
求平方根
这玩意儿怎么弄呢?欸,我们是否可以弄牛顿迭代呢?
考虑构造函数
f(x)=x2−a,这在
f(x)=0 时,
x=a,而这个
f(x)=0 的解是可以使用牛顿迭代的。
注意到
f′(x)=2x,则接下来就不难了。
具体而言,我们迭代的方法为:
xn+1=xn−f′(xn)f(xn)=xn−2xnxn2−a
这里初始迭代的你可以任选。这里迭代次数选了
105。
代码如下:
CPP#include <bits/stdc++.h>
using namespace std;
int main() {
long double n, cur;
cin >> n;
cur = n;
for (int i = 1; i <= 1e5; i++)
cur -= ((cur * cur - n) / (2 * cur));
cout << setprecision(8) << fixed << cur << '\n';
return 0;
}
求 n 次方根
这道题其实和上面的十分类似。
假设有函数
f(x)=xn−a,考虑牛顿迭代。
注意到
f′(x)=nxn−1,则:
xt+1=xt−f′(xt)f(xt)=xt−nxtn−1xtn−a
代码是容易的,这里就不给出了。
求三角函数根
举个例子,求
f(x)=x2−2cosx=0 在
[0,2π] 内的解。
同样,使用牛顿迭代法。
注意到
f′(x)=2x+2sinx,则:
xn+1=xn−2x+2sinxx2−2cosx
则同样牛顿迭代法。
求指数函数的根
好吧其实这里附赠了一些导数的内容。
例如:求
f(x)=10x+2x=100 的实根。
这里顺带讲一下指数函数的求导。(本人六年级自学,请轻点喷)
f′(x)=dxd10x+dxd2x
指数函数求导我们通常可以用链式求导法则,也即:
dxdy=dudydxdu
请注意这里形如
dxdy 一定不能想当然以为是分式。
注意到
10x=eln(10x)=exln10
使用链式求导法则:
dxdexln10=exln10⋅dxd(xln10)=exln10⋅ln10=10xln10
另外一部分直接应用普通法则即可。
则:
f′(x)=10xln10+2
这里先预处理
ln10 就行了。
这里为什么要换底数呢?原因很简单,
(ex)′=ex。
求对数函数的根
求
f(x)=log2(x)+x2−10=0 的正实数根。
那么经过上面的风雨交加的题目,这里就讲求导部分了。其它部分比较简单。
考虑换底:
log2x=ln2lnx+x2−10
则函数变为:
f(x)=ln2lnx+x2−10
换底的原因同样,因为
dxdlnx=x1。
考虑对数项求导(这里后两项省略,因为比较简单)中间使用了链式求导法则:
dxd(ln2lnx)=ln21⋅dxd(lnx)=xln21
这样就可以了。预处理
ln2 即可。
拓展应用
高维牛顿法
这个有趣的东西通常用于求解多元方程组。
对于多元方程组
F(x)=0,其中
F:Rn→Rn,则其公式为:
xn+1=xn−J−1(xn)F(xn)
Jij=∂xj∂Fi
举个例子:
{x2+y2=4ex+y=1
则雅可比矩阵为
J=[2xex2y1]
那么就简单很多了。利用线性代数的知识就可以了。
Hessian 矩阵和极小值
梯度下降法可以求无约束的极小值问题。即
minf(x)。公式:
xn+1=xn−H−1(xn)∇f(xn)
这里
H 为二阶导矩阵,也称 Hessian 矩阵。
这个就是梯度下降法,对比牛顿法复杂度少了一个
n,快了很多。
优化方法
这里给出一个优化方法,也就是当我们迭代的时候迭代的结果小于一个
ϵ 来终止,具体而言,我们可以通过这个终止条件进行终止,在不必要的精度上一定程度省去了时间。即
∣xn+1−xn∣≤ϵ。
总结
牛顿迭代法是一个非常好用的东西,我们在很多地方都将用到。
特别提醒
我们对于初始项的选择一定不能与结果误差过大,可能会导致迭代发散。例如函数成分复杂,存在拐点或者不连续的十(sang)分(xin)友(bing)好(kuang)的函数,我们需要特殊处理。顺便说一嘴:
f(x)=3x 是一个很好的检查初始值设置的函数。
或者说,对于导数为
0,迭代公式会失效,这个时候牛顿迭代法就不可做了。