平分法及牛顿法求解平方根

1. 问题描述


解非线性方程算法无论是在理论还是实际应用的角度来看,都是极为重要的。在科学和工程中,如何较好的得到一个非线性方程的数值解,是数值分析算法研究中极其重要的领域之一。我们主要讨论几个解一元非线性方程的解法,即:
f ( x ) = 0 (1) f(x) = 0 \tag{1} f(x)=0(1)
我们想要知道当 f ( x ) f(x) f(x)为非线性方程时,有什么方法求解 f ( x ) f(x) f(x)的零点,也就是上面方程的根. 例如,如何求解: n \sqrt{n} n ? 首先这个问题可以转化为求非线性方程 f ( x ) = x 2 − n = 0 (2) f(x) = x^2 - n=0 \tag{2} f(x)=x2n=0(2)的非负根。
我们可以使用迭代算法求解出 x ⋆ x^{\star} x使得 ∥ f ( x ⋆ ) − n ∥ ≤ ϵ (3) \lVert f(x^{\star}) - n\rVert \le \epsilon \tag{3} f(x)nϵ(3)


  • 介绍 线性搜索求解方法,如平分法。
  • 介绍牛顿法的理论推导、算法流程
  • 基于Python实现 平分法、牛顿法。

2 平分法


2.1 理论介绍

该算法基于这样一个观察结果,如果一个连续函数的图像在a点和b点取到的函数数值符号相反,那么该函数在两点之间至少要和x轴相交一次。
平分法及牛顿法求解平方根_第1张图片

在使用平分法解方程时,开始有一个区间 [ a , b ] [a,b] [a,b],在其端点上, f ( x ) f(x) f(x)的符号相反,该算法计算 f ( x ) f(x) f(x)的中点 x m i d = ( a + b ) / 2 (4) x_{mid} = (a + b) /2 \tag{4} xmid=(a+b)/2(4)上的值,如果 f ( x m i d ) = 0 f(x_{mid})=0 f(xmid)=0就求得一个根,算法也终止了。否则,它继续在 [ a , x m i d ] [a,x_{mid}] [a,xmid]或者 [ x m i d , b ] [x_{mid},b] [xmid,b]上查找根,至于在哪个区间上找,取决于在哪个区间的端点上满足零点定理。
因为我们不能指望平分法能够恰好发现方程的根并终止。我们需要寻找另外一种标准来终止算法。当包含某个根 x ⋆ x^{\star} x的区间 [ a n , b n ] [a_n, b_n] [an,bn]变得足够小,以至于用区间的中点 x n x_n xn逼近 x ⋆ x^{\star} x的绝对误差肯定小于某些预先选定的阈值 ϵ \epsilon ϵ( ϵ > 0 \epsilon >0 ϵ>0)我们就可以停止迭代。即当:
∣ x − x ⋆ ∣ ≤ b n − a n 2 (5) |x-x^{\star}| \le \frac{b_n - a_n}{2} \tag{5} xx2bnan(5)
我们可以停止算法。但是我们注意计算机的浮点表示等因素,如果我们选择的 ϵ \epsilon ϵ**小于一个特定机器的阈值,该算法就永远不会停止!**因此在平分法的实现中,限制算法允许执行的迭代次数是一个好的办法。

2.2 Python 实现

def binary_sqrt ( n, eps, max_iter_nums ):
    """基于平分法的平方根求解算法
    Args:
        n :     求解的值 
        eps :   迭代精度
        max_iter_nums    最大迭代次数
    """
    # 端点 a < b            iter_cnt :  记录迭代次数
    a, b = 0, n
    iter_cnt = 0
    # 中点:x        fx = x^2 - n
    x = 0
    fx = 0

    while  iter_cnt < max_iter_nums :
        x = (a + b) / 2
        # 终止条件:左端点和中点 无限接近,认为 x 已经收敛到目标值
        if x - a < eps:
            return x
        fx = x**2 - n
        if fx - n == 0:
            return x
        # 确定下一个搜索区域
        fa = a**2 - n
        if fx * fa < 0:
            b = x
        else:
            a = x
        iter_cnt += 1
        print(f'iter_cnt={iter_cnt}\t  x={x:.6f}\t  fx={fx:.6f}\t a={a:.6f}\t b={b:.6f}')
    return x

时间复杂度分析
O ( n ) = log ⁡ 2 ( ( b − a ) ϵ ) O(n) = \log_2(\frac{(b-a) }{\epsilon}) O(n)=log2(ϵ(ba))算法复杂度主要取决于 终止精度 以及搜索区间的大小。

2.3 结果分析

这里计算:binary_sqrt(2, 1e-3, 1000)
平分法的收敛过程:

iter_cnt=1	  x=1.000000	  fx=-1.000000	 a=1.000000	 b=2.000000
iter_cnt=2	  x=1.500000	  fx=0.250000	   a=1.000000	 b=1.500000
iter_cnt=3	  x=1.250000	  fx=-0.437500	 a=1.250000	 b=1.500000
iter_cnt=4	  x=1.375000	  fx=-0.109375	 a=1.375000	 b=1.500000
iter_cnt=5	  x=1.437500	  fx=0.066406	   a=1.375000	 b=1.437500
iter_cnt=6	  x=1.406250	  fx=-0.022461	 a=1.406250	 b=1.437500
iter_cnt=7	  x=1.421875	  fx=0.021729	   a=1.406250	 b=1.421875
iter_cnt=8	  x=1.414062	  fx=-0.000427	 a=1.414062	 b=1.421875
iter_cnt=9	  x=1.417969	  fx=0.010635	   a=1.414062	 b=1.417969
iter_cnt=10	  x=1.416016	  fx=0.005100	   a=1.414062	 b=1.416016
result:  1.416016

2.4 小结

平分法和折半查找非常类似,两种算法都是对查找问题的不同变化形式求解。但是平分法和折半查找法也并非等同,主要是,折半查找时严格单调的,单平分法并不要求这一点。
平方法作为解方程的通用算法的主要缺点:

  -  相对其他方法收敛速度较慢,所以在实际中很少使用这个方法
  -  无法扩展到解更一般的方程和方程组领域

平方法的优点:

  -  平方法向根收敛时,所在区间的特性是很容易检验的。而且也不用求函数导数

3 牛顿法 Newton`s Method


3.1 理论介绍

由泰勒展开公式得到:
f ( x k + 1 ) ≈ f ( x ) + ( x k + 1 − x k ) f ′ ( x k ) = 0 (6) \begin {align*} f(x_{k+1}) \approx& f(x)+(x_{k+1}- x_k) f'(x_k) =0 \end {align*} \tag{6} f(xk+1)f(x)+(xk+1xk)f(xk)=0(6)
变形得到迭代式:
x k + 1 = x k − f ( x k ) f ′ ( x k ) (7) x_{k+1} = x_k- \frac{f(x_k)}{f'(x_k)} \tag{7} xk+1=xkf(xk)f(xk)(7)
f ( x ) = x 2 − n f(x) = x^2 - n f(x)=x2n为例:
因为:
f ′ ( x ) = 2 x (8) f'(x) = 2x \tag{8} f(x)=2x(8)
得到:
x k + 1 = x k − x k 2 − n 2 x k = x k − 1 2 ( x k − n x k ) = 1 2 ( x k + n x k ) (9) \begin{align*} x_{k+1} =& x_k - \frac{x_k^2 - n}{2x_k} \\ =&x_k - \frac{1}{2}(x_k-\frac{n}{x_k}) \\ =&\frac{1}{2}(x_k + \frac{n}{x_k}) \end {align*} \tag{9} xk+1===xk2xkxk2nxk21(xkxkn)21(xk+xkn)(9)

3.2 Python 实现

def newtown_sqrt(n, eps, init_x = 1e-2):
    """基于牛顿法的平方根求解算法
    Args:
        n :     求解的值
        eps:    迭代精度
        init_x :  初始值 
    """
    x = init_x
    #    |x - x1|  用于判断是否收敛,若收敛,返回解x
    x1 = -1
    while(  abs(x - x1 ) > eps  ):
        x1 = x
       #  迭代式
        x = (x + n/x)/2
        print(f'x={x:.6f}\t  |x-x1|={abs(x - x1):.6f}\t')
    return x

求解根号2 **newtown_sqrt(2, 1e-3, 1) **迭代结果:

x=1.500000	  |x-x1|=0.500000	
x=1.416667	  |x-x1|=0.083333	
x=1.414216	  |x-x1|=0.002451	
x=1.414214	  |x-x1|=0.000002
result:  1.414214

3.3 小结

牛顿法的优势:

  - 在选择了合适的初始近似值之后能够快速收敛
  - 能够应用于更一般类型的方程和方程组

4 总结

  • 介绍了一元非线性方程的概念。
  • 介绍了线性搜索方法,如平分法。
  • 介绍了牛顿法的理论推导、算法流程。
  • 基于Python实现了 平分法、牛顿法。

你可能感兴趣的:(深度学习部署,算法,数据结构)