牛顿迭代
不要被牛顿的大名唬住,牛顿迭代其实就是一种求近似解的方法。求解过程就是对曲线做切线,然后在切线与x轴交点,然后在这个点做x轴垂线,垂线到曲线交点继续做切线,一直重复上述步骤。然后切线与曲线交点就会慢慢的趋近于X轴与曲线交点。x轴与曲线交点就是曲线方程的根,但是直线方程的跟比较好计算,计算出最近的直线方程根,约等于曲线的根。大概做曲线切线的过程如下
公式推到过程
假设曲线
f(x)
f
(
x
)
,则曲线斜率
f′(x)
f
′
(
x
)
曲线上
(xn,f(xn))
(
x
n
,
f
(
x
n
)
)
点的切线方程
y=f′(xn)(x−xn)+f(xn)
y
=
f
′
(
x
n
)
(
x
−
x
n
)
+
f
(
x
n
)
求上述方程的根(函数
f
f
的一个根(或称零点)是的定义域
D
D
中适合的元素
x
x
),若求切线与轴焦点
x
x
,则有以下方程
解方程可得
x=xn−f(xn)f′(xn)
x
=
x
n
−
f
(
x
n
)
f
′
(
x
n
)
所以切线的根为
xn−f(xn)f′(xn)
x
n
−
f
(
x
n
)
f
′
(
x
n
)
由于下一个切线点是在上边求出点做
x
x
轴垂线获得,可以推到出下一个点
依次计算
x1
x
1
、
x2
x
2
、
x3
x
3
……,那么序列将无限逼近方程的根。
举例说明
例如求3的平方根
x=3‾√2
x
=
3
2
即
x2=3
x
2
=
3
另
f(x)=x2−3
f
(
x
)
=
x
2
−
3
所以
f′(x)=2x
f
′
(
x
)
=
2
x
代入推导出的公式有
xn+1=xn−x2n−32xn=12(xn+2xn)
x
n
+
1
=
x
n
−
x
n
2
−
3
2
x
n
=
1
2
(
x
n
+
2
x
n
)
随便一个迭代的初始值,例如
x0=1
x
0
=
1
,代入上面的式子迭代有
x1=12(x0+2x0)=12(1+21)=1.5
x
1
=
1
2
(
x
0
+
2
x
0
)
=
1
2
(
1
+
2
1
)
=
1.5
x2=12(x1+2x1)=12(1.5+21.5)=1.416666...
x
2
=
1
2
(
x
1
+
2
x
1
)
=
1
2
(
1.5
+
2
1.5
)
=
1.416666...
x3=12(x2+2x2)=12(1.416666+21.416666)=1.414218...
x
3
=
1
2
(
x
2
+
2
x
2
)
=
1
2
(
1.416666
+
2
1.416666
)
=
1.414218...
……
求
a
a
的平方根 即
x2=a
x
2
=
a
另
f(x)=x2−a
f
(
x
)
=
x
2
−
a
所以
f′(x)=2x
f
′
(
x
)
=
2
x
代入推导出的公式有
xn+1=xn−x2n−a2xn=12(xn+axn)
x
n
+
1
=
x
n
−
x
n
2
−
a
2
x
n
=
1
2
(
x
n
+
a
x
n
)
求
a
a
的次方根
x=a‾√k
x
=
a
k
即
xk=a
x
k
=
a
另
f(x)=xk−a
f
(
x
)
=
x
k
−
a
所以
f′(x)=kxk−1
f
′
(
x
)
=
k
x
k
−
1
代入推导的公式有
xn+1=xn−xkn−akxk−1n=k−1kxn+akxk−1n
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
二分查找
二分查找(折半查找),就是每次都在序列中找最中间的那个元素,根据元素与目标元素大小比较在剩下的一般继续查找,如此循环值到找到为止。
二分查找比较常见的场景就是在一个有序数组中查找某个值,代码一般如下
private int binarySearch(long[] a, int fromIndex, int toIndex,long key) {
int low = fromIndex;
int high = toIndex - 1;
while (low <= high) {
int mid = (low + high) >>> 1;
long midVal = a[mid];
if (midVal < key)
low = mid + 1;
else if (midVal > key)
high = mid - 1;
else
return mid; // key found
}
return -(low + 1); // key not found.
}
当然也可以用二分查找来求平方根,其实就是把上边的查找值变成找平方根而已。比较条件换成 mid2 m i d 2 与 num n u m 的比较。
求平方根算法具体算法(Java)
private static final double deviation = 0.00001;//求值精度
/**
* 返回平方根,判断如果正数正好是平方根就返回,否则返回小数的
* @param x
* @param mid
* @return
*/
private double getSquare(double x, double mid) {
long a = Math.round(mid);
if (a * a == x) {
return a;
} else {
return mid;
}
}
/**
* 牛顿迭代求平方根
* @param num
* @return
*/
public double sqrtNewton(double num) {
double x = num;
double nextX;
while (true) {
nextX = x - (x * x - num) / (2 * x);
if (Math.abs(nextX * nextX - num) <= deviation) {
return getSquare(num, nextX);
}
x = nextX;
}
}
/**
* 二分查找求平方根
* @param num
* @return
*/
public double sqrtBinary(double num) {
if (num == 0 || num == 1) {
return num;
} else {
double start = 0;
double end = num;
double mid;
while (true) {
mid = (start + end) / 2;
if (mid * mid == num || Math.abs(mid * mid - num) <= deviation) {
return getSquare(num, mid);
} else if (mid < num / mid) {
start = mid;
} else {
end = mid;
}
}
}
}
我的博客:http://yuntaoblog.com/2018/03/29/牛顿迭代与二分查找开平方/