如何优雅的求平方根

F&Q

承太郎:DIO,来做一道题

DIO:承太郎。来吧。(JOJO立)

承太郎:求一个数的算术平方根,保留整数部分,简单吧,你一定很快就能做出来。

DIO:Math.sqrt(x),太简单了。hahaha

承太郎:你居然说用Math.sqrt(),不能用库函数!!!不能用库函数!!!不能用库函数!!!やれやれだぜ(真是够了),

DIO:这!!砸瓦鲁多!!F

二分法

求一个正整数的算术平方根的话,这个平方根一定不会大于这个正整数的二分之一。所以我们可以利用二分法从区间[1,x / 2]中来找这个平方根

关于二分搜索查考这篇文章:https://labuladong.gitbook.io/algo/di-ling-zhang-bi-du-xi-lie/er-fen-cha-zhao-xiang-jie

class Solution {
    public int mySqrt(int x) {
        // 二分法
        // 0的任何次方等于0
        if (x == 0) return 0;
        long left = 1;
        long right = x / 2;
        while (left < right) {
            long mid = (left + right + 1) / 2; // 不考虑越界
            long v = mid * mid;
            if (v > x) right = mid - 1;
            else left = mid;
        }
        return (int)left;
    }
}

值得注意的是取mid这里,我们一定要取区间的右中位数,例如求9的平方根,当我们计算到区间【3, 4】的话,如果mid按照如下取值的话

mid = left + (right - left ) / 2

此时,mid=3,left = mid,此时会循环查找【3,4】的值。

牛顿迭代法

重点来了,这道题更牛逼的算法还是牛顿迭代法(万能的牛顿,你还有啥不会的),其实准确的叫牛顿-拉夫逊(拉弗森)方法,又是一个被牛顿名声盖过的人,可怜拉弗森一秒钟。。。。

好了。在这里我不讲牛顿迭代法如何得来,反正从泰勒级数展开公式推导出的,说了你也不懂(皮一下),我就从结论入手。

先看一图:

                牛顿法动图

该算法的思想是:

    迭代的过程中,使x不停的逼近与 f(x)=0,直到迭代收敛,上图不难看出来

因为牛顿法(下面会给出证明链接),所以我们可以令f(x) = x^2 - c

得出,x点切线方程:

变形可得:

又令f(x) = 0

所以得:

 

 

所以:

 

化简得出:

那么,公式推导到此结束,剩下的就该写代码了

class Solution {
public:
    int mySqrt(int x) {
        long v = x;
        while (v * v > x)
            v = (v + x / v) / 2;  // 公式
        return (int)v;  // 取整
    }
};

 

当然,如果我们不取整的话,只需要把long变成double型,注意有些数的算术平方根是算不出的,我们需要一个变量来保存上一步求出的数,用当前的数减去上一步求出的数 小于 一个精度 即可。

看代码吧,我相信我的写作功底不是太好(留下了没有技术的泪)。

#define v 0.0000001
double sqrt(int x)
{
	double pre = 0;	// 上一步算的
	double curr = x;// 当前算的
	while (abs(curr - pre) > v)
	{
		pre = curr;
		curr = (curr + x / curr) / 2;
	}
	return pre;
}

输入:5

输出:2.23607

如果要求精度越高,我们只需要改变v的值就行了。

F&Q

承太郎:好吧,算你厉害。如果你用替身攻击,当我没说。

DIO:嘿嘿

承太郎:对了你这些公式是怎么搞出来的。

DIO:推荐你一个在线绘制公式的网站吧:http://www.wiris.com/editor/demo/en/developers

承太郎:很赞。

承太郎:你为啥一会用java写代码,一会儿用cpp、python

DIO:全凭喜好,语言不重要,重要的是思想,哪个语言表达的逻辑清晰就用那个,不过我平时还是写Java和Python。

参考资料:

《JoJo的奇妙冒险》

《如何通俗易懂地讲解牛顿迭代法求开方?数值分析?》

力扣

csdn

外链1:http://lock2016.xyz/blog/article/11

外链2:https://noncover.github.io/

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值