求平方根的几种方法

求解 这里写图片描述是我们会常常遇到的,c++里一个sqrt(x)就解决了。这个值怎么得到的,倒是个有趣的问题。比较容易想到的是把这个问题转换为 这里写图片描述,接着就一个个试了……有人会说妈的智障,好吧,怪我没讲清楚,试要试得有水平,不能瞎试吧。其中,二分法就是一个试的有水平的方法,二分法简而言之就是找有可能范围中的中间的那个数来试。下面会谈到二分法、牛顿迭代法和一种神奇的方法 。


二分法

这里写图片描述 为例,可能的范围是[0, 10],取中间的值5,试下乘法口诀表五五二十五,大了。可能的范围的就缩小为了[0, 5],接着取2.5,小了,取[2.5,5]……又有人说了,这得试到什么时候啊,这里就需要设定一个误差err,当 这里写图片描述 时就认为算对了。

c++代码如下:

float dichotomyMethod(float n, float err)
{

    float bigNum = n;
    float smallNum = 0;
    float midNum = 0;
    float errTemp = 0;

    do
    {
        if(errTemp > 0)
            bigNum = midNum;
        else
            smallNum = midNum;
        midNum = (bigNum + smallNum) / 2.0;
        errTemp = midNum * midNum - n;

    }while(fabs(errTemp) > err);

    return midNum;
}

牛顿迭代法

之前一直不知道这种方法,直到上了一门《数值分析》的课。当然是考试前复习的时候才直到的,O(╯□╰)O 。这种方法能够花比较少的次数接近结果,在单根附近有平方收敛。

对于这里写图片描述来说可以通过 这里写图片描述 来迭代求解,直到达到精度的要求。

上面的式子很简单,几何上的意义是点Xn处的切线与x轴得到的交点就是 Xn+1。下面这张动图能比较好说明。

newton

代数上是对 f(x) 进行泰勒展开,并取前两项。这里写图片描述,由于 X0是零点,第一项则为0,即 这里写图片描述,和之前提到的迭代表达式一致。

c++代码如下:

float newtonIterationMethod(float n, float err)
{
    float x = n;
    float temp = x;
    do
    {
        temp = x;
        x = (x + n / x) / 2.0;

    }while(fabs(x * x - n) > err);

    return x;
}

对比下以上两种方法所花的时间。计算1000次总时间的对比:

  • 二分法 625us
  • 牛顿迭代法 193us

牛顿迭代法胜出,差距还是比较明显。


神奇方法

博客上看到一种很神奇的方法,是来自游戏Quake III的源代码,求得是这里写图片描述。代码如下:

float InvSqrt (float x)
{
    float xhalf = 0.5f*x;
    int i = *(int*)&x;
    i = 0x5f3759df - (i>>1);
    float y = *(float*)&i;
    y = y*(1.5f - xhalf*y*y);
    return y;
}

对于游戏来说,速度比精度重要,不像科学计算那样。这种方法做了一些近似,精度不一定高,但是速度快。可以看到,这方法仅仅用了一句i = 0x5f3759df - (i>>1);就完成了计算,后面加了牛顿迭代提高精度(想得到更高的精度可以多迭代几次)。

具体原理可以看上面提高的博客,反正我是没看懂……站在数学制高点的人编程真的就是开挂啊,喂。

三种方法加自带函数的时间对比(1000次,只是宏观上的对比,编译器可能会有优化):

  • 二分法 600us
  • 牛顿迭代法 150us
  • 神奇方法 26us
  • 自带sqrt 19us

有趣的是,据说提到的这种神奇的方法在10几年前比自带的sqrt函数快4倍左右,现在编译器各种优化加硬件上的变化,也许也有算法上的改变,使得自带的sqrt函数变快了。一个sqrt都能玩的这么溜,也是服了。


csdn博客mardwon模式不能渲染Latex公式真的烦!

  • 2
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值