C++求解开根号

一般使用两种方法,二分法和牛顿迭代法
一般会让有两种求解结果,一种是求解其整数部分,另一种是求解浮点数并给出精度

二分法

思路
x的平方根的整数部分肯定是在0~x之间的,所以我们可以直接将其转换为在以0开头的有序数组中使用二分查找定位该数字(这数值就是mid:每次二分查找的中间值),那么mid^2一定是最接近x的。

需要定义的变量
l :表示左边值
r:表示右边值
mid:临时存储 l+r /2的中间值

n值的临界条件判断
当mid * mid > x,则 mid 取 l 到 mid -1的中间数,继续循环,直到mid * mid < x,mid就是要找的数 ;
当mid * mid <= x ,则mid取 mid +1 到 r 的中间数,并将mid 赋值给n ,直到两边界限重合,n就是要找的数。

时间复杂度:O(logN)

劣势:数值太大容易超过限制,可以做下修改
将临界的判断条件改成
mid > x / mid,则 mid 取 l 到 mid -1的中间数,继续循环,直到mid < x / mid,mid就是要找的数
当mid <= x / mid ,则mid取 mid +1 到 r 的中间数,并将mid 赋值给n ,直到两边界限重合,n就是要找的数。

    //整数二分
    //边界划分[l, mid - 1] [mid, r]
    int bsqrt(int x)
    {
        if(x == 0||x == 1) return x;
        int r = x;
        int mid = 0;
        int l = 0;
        while(l < r)
        {
            mid = (int)(l/2.0 + r/2.0 + 0.5);//防止超出int范围
            if(mid <= x / mid) l = mid;
            else r = mid - 1;
        }
        return l;
    }

直接浮点数求解二分开根号,注意设置精度

    //使用浮点数二分
    double bsqrt(double x)
    {
        const double esp = 1e-6;//精度
        double r = x, l = 0.0;
        while(r - l > esp)
        {
            double mid = r / 2.0 + l / 2.0;//防止超出范围
            if(mid - x / mid >= esp) r = mid;//防止超出范围
            else l = mid; 
        }
        return l;
    }

牛顿迭代法

来自百度文库

求n的平方根,即计算x2=nx^{2}= nx2=n的解,令f(x)=x2−nf(x)=x^{2}-nf(x)=x2n,相当于求解f(x)=0f(x)=0f(x)=0的解。
1.首先取猜测x0x_0x0(例如可以设初次猜测值为x/2x/2x/2),如果x_0不是解,做一个经过(x0,f(x0))这个点的切线,与xxx轴的交点为x1x_1x1。 同理,如果x1x_1x1不是解,做一个经过(x1,f(x1))(x_1,f(x_1))(x1,f(x1))这个点的切线,与x轴的交点为x2x_2x2。 以此类推。 以这样的方式得到的xi会无限趋近于f(x)=0的解。

2.判断xix_ixi是否是f(x)=0f(x)=0f(x)=0的解有两种方法: 第一种是直接计算f(xi)f(x_i)f(xi)的值判断是否为0,第二种是判断前后解xix_ixixi−1x_{i-1}xi1是否无限接近(误差精度)。经过(xi,f(xi))(x_i, f(x_i))(xi,f(xi))这个点的切线方程为f(x)=f′(xi)(x−xi)+f(xi)f(x) = f'(x_i)(x - x_i)+f(x_i)f(x)=f(xi)(xxi)+f(xi) ,其中f′(x)f'(x)f(x)f(x)f(x)f(x)的导数。(本例中为2x2x2x)令切线方程等于0,即可求出x(i+1)=xi−f(xi)/f′(xi)x(i+1)=x_i - f(x_i) / f'(x_i)x(i+1)=xif(xi)/f(xi)。在此题中,化简可得到迭代公式xi+1=xi−(xi2−n)/(2xi)x_{i+1}=x_i - (x_i^{2} - n) / (2x_i)xi+1=xi(xi2n)/(2xi)
在这里插入图片描述
整数部分

#define error 1e-9//误差精度
class Solution {
public:

   //inline double df(int& x, double& x0){return x0 - (x0 * x0 - x)/(2 * x0);}//化简一下(x0 + x / x0) / 2
    inline double df(int& x, double& x0){return (x0 + x/ x0) / 2;}
    int mySqrt(int x)
    {
        if(x == 0 || x == 1) return x;
        double x0 = x / 2.0;
        double x1 = df(x, x0);
        
        while (abs(x0 - x1)  >= error)
        {
            x0 = x1; 
            x1 = df(x, x0);
        }
        return (int) x1;
    }
};

化简下

class Solution {
public:
    int mySqrt(int x) {
    	if(x == 0 || x == 1) return x;
        long res = x;
        while (res * res > x) 
        {
            res = (res + x / res) / 2;
        }
        return res;
    }
};

返回浮点数

#define error 1e-9//误差精度
class Solution {
public:

    //inline double df(int& x, double& x0){return x0 - (x0 * x0 - x)/(2 * x0);}//化简一下x0/2 + x/ (2x0)
    inline double df(int& x, double& x0){return (x0 + x/ x0) / 2;}
    double mySqrt(int x)
    {
        if(x == 0 || x == 1) return x;
        double x0 = x / 2.0;
        double x1 = df(x, x0);
        
        while (abs(x0 - x1)  >= error)
        {
            x0 = x1; 
            x1 = df(x, x0);
        }
        return  x1;
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

VoladorL

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值