最近听说开平方算法挺难写,自己思考一下确实这些库函数只是一直在用,但是很少去思考如何实现的,sqrt在排序中使用频率非常的高,所以就研究了一下。大概有三种实现方式。
一、用二分的方法
每次用中间数就试,如果大就到左区间选取中间数试,如果小就到右区间找中间数试,采用不断逼近的方式计算平方根,这种方式迭代次数有点多,且每次试验都要进行运算,效率不是很高,但是思路简单,巧妙的运用了二分的方法。
#define eps 0.00000001 float SqrtByBisection(float n) { //小于0的按照你需要的处理 if(n < 0) return n; float mid,last; float low,up; low=0,up=n; mid=(low+up)/2; do { if(mid*mid>n) up=mid; else low=mid; last=mid; mid=(up+low)/2; } //精度控制 while(fabs(mid-last) > eps); return mid; }二、牛顿迭代法
这种方式的原理就是通过f(x) = x^2 - a = 0 的切线来逼近x^2 -a =0的的根,根号a就是f(x) =0的一个正实根,这个函数的导数是2x,也就是切线的斜率是2x,也就是x-f(x)/2x是比x更接近的近似值,带人方程得到f(x) = (x+a/x) / 2是更近似的值
float SqrtByNewton(float x) { float val = x;//最终 float last;//保存上一个计算的值 do { last = val; val =(val + x/val) / 2; }while(fabs(val-last) > 0.0001); return val; }三、神一样的算法
float InvSqrt(float x) { float xhalf = 0.5f*x; int i = *(int*)&x; // get bits for floating VALUE i = 0x5f3759df - (i>>1); // gives initial guess y0 x = *(float*)&i; // convert bits BACK to float x = x*(1.5f-xhalf*x*x); // Newton step, repeating increases accuracy return x; }
原文地址:http://blog.csdn.net/wdxin1322/article/details/38045907