title: 二分法 牛顿法 求sqrt
comments: true
categories:

  • Algorithm
    tags:
  • Algorithm
  • C++
    date: 2019-03-21 10:47:38

使用二分法

首先确定二分法查找的首尾区间,然后根据abs(mid^2-target)<eps的误差进行区间的移动,寻找满足精度的位置

存在的问题:

  • 第一步寻找合适的搜索区间,我们从函数曲线上可以看出,y=x和y=√x在x=1时交集;
  • 当待开根号数在(0,1)之间时,搜索区间也在(0,1),当待开根号数tar>1时,区间在[1,x]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3el4PZu0-1576236781089)(http://po7b8zci3.bkt.clouddn.com/15531498785073.jpg)]

实现

float found(float x,float eps,float s,float e){
    float mid = s+(e-s)/2.0;
    float tmp = mid*mid - x;

    if(abs(tmp) <= err){
        return mid;
    }
    if(tmp >0){
        return found(x,eps,s,mid);
    }else{
        return found(x,eps,mid,e);
    }
}

float sqrt(float x,float eps){
    if (x<0) return -1;
    if (x==0) return 0;

    if(0<x && x<1){
        return found(x,eps,0.,1.);
    }else{
        return found(x,eps,1,x);
    }
    
}

二分法的非递归实现

float found(float x,float eps,float s,float e){
    float mid = (e+s)/2.0;
    float tmp =  mid*mid - x;
    
    while(abs(tmp) > eps){
        printf("cnt %d %f %f %f \n ",cnt,s,e,mid);

        if(tmp>0){
            e = mid;
        }else{
            s = mid;
        }
        mid=(s+e)/2;
        tmp = mid*mid - x;
    }
    return mid;
}

使用牛顿迭代法

仔细思考一下就能发现,我们需要解决的问题可以简单化理解。

  • 从函数意义上理解:我们是要求函数f(x) = x²,使f(x) = num的近似解,即x² - num = 0的近似解。
  • 从几何意义上理解:我们是要求抛物线g(x) = x² - num与x轴交点(g(x) = 0)最接近的点。

实现


float NewTown(float x,float eps){
    float x0,x1= x/2.0;

    int cnt=0;

    while(abs(x1-x0) >= eps){
        x0 = x1;
        printf("cnt: %d %f \n ",cnt,x0);
        x1 = x0 - (x0*x0-x)/(2.0*x0);
// x1 = 1.0/2*(x0+x/x0);
        cnt++;
    }
    
    return x1;
}

使用牛顿迭代法求多项式的一个根

定区间,找中点,中值计算两边看。 
同号去,异号算,零点落在异号间。

实现


float NewTown2(){
    float x,x1=1;
    int a=1,b=2,c=3,d=4;

    float f,f1;

    while(abs(x1-x) >0.001){
        x=x1;
        f = ((a*x+b)*x+c)*x + d;
        f1 = (3*a*x+2*b)*x+c;
        x1 = x - f/f1;
    }

    printf("newtown2 %.10f",x1);
    return x1;

}

牛顿迭代法

五次及以上多项式方程没有根式解(就是没有像二次方程那样的万能公式)

  • 牛顿迭代法(Newton’s method),它是牛顿在17世纪提出的一种在实数域和复数域上近似求解方程的方法。

  • 切线是曲线的线性逼近

  • 求高阶方程式的近似解,
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-t6ijUoIP-1576236781090)(http://po7b8zci3.bkt.clouddn.com/15531543539924.jpg)]

比如我们要开平方根,则可以转换为求x^2 - a = 0的实数根,根据x_n+1 = x_n - f(x_n)/f’(x_n) ,不断迭代新的切线,直到找到近似解,f(x)和x轴的交点

不收敛的情况:

驻点

起始点不幸选择了驻点,从几何上看切线根本没有根。

越来越远离的不收敛

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-v0fcY15e-1576236781091)(http://po7b8zci3.bkt.clouddn.com/15531548601931.jpg)]

循环震荡的不收敛

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PskEgjVi-1576236781093)(http://po7b8zci3.bkt.clouddn.com/15531550374784.jpg)]

不能完整求出所有的根

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-D5WtvezB-1576236781096)(http://po7b8zci3.bkt.clouddn.com/15531549206795.jpg)]

总结

应用牛顿-拉弗森方法,要注意以下问题:
函数在整个定义域内最好是二阶可导的
起始点对求根计算影响重大,可以增加一些别的判断手段进行试错

牛顿法求极值 梯度下降求极值

其实牛顿迭代法也可以很方便的求极值,只要x=x−f’(x)/f"(x)
这样求的就是,f’(x)与x轴的交点,既导数的零点,也即是f(x)的极值点

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-feBh9guZ-1576236781101)(http://po7b8zci3.bkt.clouddn.com/15531575573419.jpg)]