C/C++二分法实现开平方

1.数学原理

求一个数c的平方等价于求方程 x 2 = c x^{2} = c x2=c 的解,方程解的问题可以转换为函数零点问题。即求函数 f ( x ) = x 2 − c f(x) = x^{2}-c f(x)=x2c的零点。

零点定理:若f(a)f(b)<0则∃m ∈ \in [a,b],有f(m) = 0

由零点定理可知,只需估计a,b的值,令m=(a+b)/2,然后不断二分就可以得到更加小的区间[a,b]。使得 f ( m ) ≃ 0 f(m) \simeq 0 f(m)0,此时的m就是所求。

现在问题就是如何选取a,b的值,上述可知:
1.a,b,m必须满足不等式 a ≤ m ≤ b a\le m \le b amb
2.由于开方的结果必然为正整数 (即 m ≥ 0 m\ge0 m0),因此可以取下界 a = 0 , 有 f ( a ) = − c < 0 a=0,有f(a) = -c<0 a=0f(a)=c<0
3.因为f(a)<0,则f(b)>0才有f(a)f(b)<0,所以考虑满足f(b)>0的点。考虑b=c有,当 c ≥ 1 时 , f ( b ) = c 2 − c > 0 可 取 , 当 0 ≤ c < 1 时 f ( b ) < 0 不 符 合 c\ge1 时,f(b) = c^{2}-c>0可取,当0\le c<1时f(b) <0不符合 c1f(b)=c2c>0,0c<1f(b)<0。可见b要取一个大于c的值,不妨令b = c+k(k>0) 使得 f ( b ) = c 2 − c + k > 0 = > ( c − 1 2 ) 2 + ( k − 1 4 ) > 0 f(b) = c^{2}-c+k>0 => (c-\frac{1}{2}) ^{2}+(k-\frac{1}{4})>0 f(b)=c2c+k>0=>c21)2+(k41)>0
= > k > 1 4 =>k>\frac{1}{4} =>k>41
不妨就令k = 0.25 故 b = c+k = c+0.25

2.代码实现
#include <iostream>
#include<iomanip>
#include <stdlib.h>
#include <cstring>
#include <cfloat>

//控制精度,也可以直接使用double中定义的常量: DBL_EPSILON
#define PRESCION 0.00001
using namespace std;


//零点定理二分开平方
double sqrt(double c)
{
    double a = 0,b = c+0.25;
    double m;
    while(1)
    {
        //1.二分取区间[a,b]的中点
        m = (a+b)/2;

        //2.使用区间长度控制精度
        //注意:这个判断必须写在3的前面,否则a或者b已经更新为m必然会有m-a=0||b-m=0,导致只循环1次就退出
        if(b - m < PRESCION||m - a <PRESCION)
            break;

        //3.使用零点定理f(m)f(b)<0来选择区间   左区间:[a,m),右区间:(m,b]
        //或由于0<a<m<b,即a,m,b都大于0,只往0+的方向趋近也可直接比较m^2与c的大小来选择区间 if((m*m - c)<0)
        if((m*m - c)*(b*b - c)<0)
            a = m;
        else
            b = m;
    }
    return m;
}




int main()
{
    double n;
    cin>>n;
    //控制输出位数
    cout<<setiosflags(ios::fixed)<<setprecision(10)<<sqrt(n)<<endl;
    return 0;
}

参考文章

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值