如果您无法下载资料,请参考说明:
1、部分资料下载需要金币,请确保您的账户上有足够的金币
2、已购买过的文档,再次下载不重复扣费
3、资料包下载后请先用软件解压,在使用对应软件打开
HYPERLINK"http://www.cnblogs.com/jyshis/archive/2011/09/08/2171869.html"一个Sqrt函数引发的血案源码下载地址:HYPERLINK"http://blog.redfox66.com/post/story-about-sqrt.aspx"\t"_blank"http://blog.redfox66.com/post/story-about-sqrt.aspx好吧,我承认我标题党了,不过既然你来了,就认真看下去吧,保证你有收获。我们平时经常会有一些数据运算的操作,需要调用sqrt,exp,abs等函数,那么时候你有没有想过:这个些函数系统是如何实现的?就拿最常用的sqrt函数来说吧,系统怎么来实现这个经常调用的函数呢?虽然有可能你平时没有想过这个问题,不过正所谓是“临阵磨枪,不快也光”,你“眉头一皱,计上心来”,这个不是太简单了嘛,用二分的方法,在一个区间中,每次拿中间数的平方来试验,如果大了,就再试左区间的中间数;如果小了,就再拿右区间的中间数来试。比如求sqrt(16)的结果,你先试(0+16)/2=8,8*8=64,64比16大,然后就向左移,试(0+8)/2=4,4*4=16刚好,你得到了正确的结果sqrt(16)=4。然后你三下五除二就把程序写出来了:floatSqrtByBisection(floatn)//用二分法{if(n<0)//小于0的按照你需要的处理returnn;floatmid,last;floatlow,up;low=0,up=n;mid=(low+up)/2;do{if(mid*mid>n)up=mid;elselow=mid;last=mid;mid=(up+low)/2;}while(abs(mid-last)>eps);//精度控制returnmid;}然后看看和系统函数性能和精度的差别(其中时间单位不是秒也不是毫秒,而是CPUTick,不管单位是什么,统一了就有可比性)从图中可以看出,二分法和系统的方法结果上完全相同,但是性能上整整差了几百倍。为什么会有这么大的区别呢?难道系统有什么更好的办法?难道。。。。哦,对了,回忆下我们曾经的高数课,曾经老师教过我们“牛顿迭代法快速寻找平方根”,或者这种方法可以帮助我们,具体步骤如下:求出根号a的近似值:首先随便猜一个近似值x,然后不断令x等于x和a/x的平均数,迭代个六七次后x的值就已经相当精确了。例如,我想求根号2等于多少。假如我猜测的结果为4,虽然错的离谱,但你可以看到使用牛顿迭代法后这个值很快就趋近于根号2了:(4+2/4)/2=2.25(2.25+2/2.25)/2=1.56944..(1.56944..+2/1.56944..)/2=1.42189..(1.42189..+2/1.42189..)/2=1.41423......这种算法的原理很简单,我们仅仅是不断用(x,f(x))的切线来逼近方程x^2-a=0的根。根号a实际上就是x^2-a=0的一个正实根,这个函数的导数是2x。也就是说,函数上任一点(x,f(x))处的切线斜率是2x。那么,x-f(x)/(2x)就是一个比x更接近的近似值。代入f(x)=x^2-a得到x-(x^2-a)/(2x),也就是(x+a/x)/2。相关的代码如下:floatSqrtByNewton(floatx){floatval=x;//最终floatlast;//保存上一个计算的值do{last=val;val=(val+x/val)/2;}while(abs(val-last)>eps);returnval;}然后我们再来看下性能测试:哇塞,性能提高了很多,可是和系统函数相比,还是有这么大差距,这是为什么呀?想啊想啊,想了很久仍然百思不得其解。突然有一天,我在网上看到一个神奇的方法,于是就有了今天的这篇文章,废话不多说,看代码先:floatInvSqrt(floatx){floatxhalf=0.5f*x;inti=*(int*)&x;//getbitsforfloatingVALUEi=0x5f375a86-(i>>1);//givesinitialguessy0x=*(float*)&i;//convertbitsBACKtofloatx=x*(1.5f-xhalf*x*x);//Newtonstep,repeatingincreasesaccuracyx=x*(1.5f-xhalf*x*x);//Newtonstep,repeatingincr