目录:
Sqrt算法之原理
起因
- 2018/7/8刷leetcode题碰到一题:
原题:
实现 int sqrt(int x) 函数。 计算并返回 x 的平方根,其中 x 是非负整数。 由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去。
自己想法
- 通过遍历的方法 相乘
代码实现:
def mySqrt(self, x): """ :type x: int :rtype: int """ i=1 sum=0; while True: if i*i>x: return i-1 else: i+=1
- 结果:悲剧超时,自己也觉得有非常多的无效计算
百度后
牛顿迭代法
- 作用
并不是所有的方程都有求根公式,或者求根公式很复杂,导致求解困难。利用牛顿法,可以迭代求解。 - 请平方根方程式 x^2-a=0 的根
- 公式介绍:
我们每次枚举一个值X0,代入方程看是否为根,不是的话则将X0的值变为:
X0=X0−F(X0)/F′(X0)
(其中F′(x) 为 F(x) 的导数)
其证明过程借用了高数中的基本知识泰勒级数,此处不再赘述。 应用求平方根
对于该问题我们可以使用牛顿迭代+高精度除法。 我们以开平方根举例 对于一个已知的数 a,开根号本质上是求一个X0 使得 X20=a 也就是求函数 F(x)=x^2−a 的根 因为F′(x)=2x 故每次迭代,x的变化值为: x=x−(x^2−a)/(2x)=(x+a/x)/2
代码实现:
def mySqrt(self, x): """ :type x: int :rtype: int """ r=x while r*r>x: r=(r+x//r)//2 return r
底层优化
虽然sqrt() 已经很方便,但确实是存在比其更强大的手写算法,这个黑科技来自游戏雷神之锤3的源代码:(细节见末尾推荐文章)int sqrt(float x) { if(x == 0) return 0; float result = x; float xhalf = 0.5f*result; int i = *(int*)&result; i = 0x5f375a86- (i>>1); // what the fuck? result = *(float*)&i; result = result*(1.5f-xhalf*result*result); // Newton step, repeating increases accuracy result = result*(1.5f-xhalf*result*result); return 1.0f/result; }
推荐链接学习
地址:详细sqrt算法解析地址