牛顿法(又称:牛顿迭代法)能快速逼近很多方程的解,自然可以用来开任意平方。
求 a \sqrt{a} a,即求 x 2 − a = 0 x^2 - a = 0 x2−a=0的正根。更一般的,求 a k \sqrt[k]{a} ka,即求 x k − a = 0 x^k - a = 0 xk−a=0的正根。
注意:牛顿法只能逼近解,不能计算精确解。 不过实际应用中,我们都不要求绝对精确的解,只要精度足够高就好了,所以它的应用非常广泛。
牛顿法
假设方程 f ( x ) = 0 f(x) = 0 f(x)=0 在 x 0 x_0 x0 附近有一个根,那么用以下的迭代式子:
x n + 1 = x n − f ( x n ) f ′ ( x n ) x_{n+1} = x_n - \frac{f(x_n)}{f^{'}(x_n)} xn+1=xn−f′(xn)f(xn)
依次计算 x 1 , x 2 , x 3 , . . . . x_1,x_2,x_3,.... x1,x2,x3,....,那么序列将无限逼近方程的根。
牛顿迭代法的原理很简单,其实是根据1在1附近的值和斜率,估计1和1轴的焦点。任选一点,做与函数的垂直连接线,求函数上该点切线,将切线与x轴的交点作为新的点,重复当前步骤,直至毕竟正确的解。 具体展示如图:
图片来源:牛顿法示例
牛顿法开方
令: f ( x ) = x 2 − a f(x) = x^2 - a f(x)=x2−a,所以 f ( x ) f(x) f(x)的一次导数是 f ( 1 ) ( x ) = 2 x f^{(1)}(x) = 2x f(1)(x)=2x,牛顿迭代式为:
x n + 1 = x n − x n 2 − a 2 x n = 1 2 ( x n + a x n ) x_{n+1} = x_n - \frac{x^2_n - a}{2x_n} = \frac1 2(x_n + \frac a x_n) xn+1=xn−2xnxn2−a=21(xn+xan)
随便一个迭代的初始值,例如 x 0 = 1 x_0 = 1 x0=1,代入上面的式子迭代:例如计算 2 \sqrt{2} 2,即 a = 2 a = 2 a=2
x 0 = 1 , x 1 = 1 2 ∗ ( 1 + 2 1 ) = 1.5 x_{0} = 1, x_{1} = \frac 1 2 * (1 + \frac 2 1)=1.5 x0=1,x1=21∗(1+12)=1.5
依次往下计算可得 2 = 1.4121356... \sqrt{2} = 1.4121356... 2=1.4121356...
由此我们可以用代码实现为:
public static double sqrt(double c) {
if (c < 0) return Double.NaN;
double err = 1e-7; //精度不要太高,否则较大数运算时间过长
double t = c; //t is a number we just guess
while (Math.abs(c - t*t) > err)
t = (c/t + t) / 2.0;
return t;
}
牛顿法开任意次方
求 a k \sqrt[k]{a} ka的递推式是:
x n + 1 = x n − x n k − a k x n k − 1 = k − 1 k x n + a k x n k − 1 x_{n+1} = x_n - \frac{x^k_n - a}{kx^{k - 1}_n} = \frac{k - 1}{k}x_n + \frac a {kx^{k - 1}_n} xn+1=xn−kxnk−1xnk−a=kk−1xn+kxnk−1a