cream 的qsqrt 及其原理

首先,是creamk 的qsort:

  1. float Q_rsqrt( float number )
  2. {
  3. long i;
  4. float x2, y;
  5. const float threehalfs = 1.5F;
  6. x2 = number * 0.5F;
  7. y = number;
  8. i = * ( long * ) &y; // evil floating point bit level hacking
  9. i = 0x5f3759df - ( i >> 1 ); // what the fuck?
  10. y = * ( float * ) &i;
  11. y = y * ( threehalfs - ( x2 * y * y ) ); // 1st iteration
  12. // y = y * ( threehalfs - ( x2 * y * y ) ); // 2nd iteration, this can be removed
  13. #ifndef Q3_VM
  14. #ifdef __linux__
  15. assert( !isnan(y) ); // bk010122 - FPE?
  16. #endif
  17. #endif
  18. return y;
  19. }

//这段代码求解的是1.0/sqrt(x);

以及c++中简单的实现代码:

1
2
3
4
5
6
7
8
9
10
11
12
static  float  CarmackSqrt ( 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
        x = x*(1.5f - xhalf*x*x);     // Newton step, repeating increases accuracy
        x = x*(1.5f - xhalf*x*x);     // Newton step, repeating increases accuracy
        return  (1 / x);
}

     经过测试,这段代码是stl里的sqrt效率的4倍。辣么问题来了,为什么这段代码这么高效呢?

      首先,creamk用了求解平方根的一般方法:牛顿迭代法,其原理如下:

   
 
     设r是   的根,选取x0作为r的初始近似值,过点  做曲线   的切线L,L的方程为   ,求出L与x轴交点的横坐标   ,称x1为r的一次近似值。过点   做曲线 的切线,并求该切线与x轴交点的横坐标   ,称  为r的二次近似值。重复以上过程,得r的近似值序列,其中,  称为r的  次近似值,上式称为牛顿迭代公式。
    用牛顿迭代法解非线性方程,是把非线性方程  线性化的一种近似方法。把   在点x0 的某邻域内展开成泰勒级数
 
,取其线性部分(即泰勒展开的前两项),并令其等于0,即
 
,以此作为非线性方程
   
的近似方程
    ,则其解
 
, 这样,得到牛顿迭代法的一个迭代关系式:
 
   已经证明,如果是连续的,并且待求的零点是孤立的,那么在零点周围存在一个区域,只要初始值位于这个邻近区域内,那么牛顿法必定收敛。 并且,如果不为0, 那么牛顿法将具有平方收敛的性能. 粗略的说,这意味着每迭代一次,牛顿法结果的有效数字将增加一倍。
  多次迭代后,数字必收敛于方程的根。
 
 

 
     第二点便是他用到了魔数0x5f3759df,使得迭代法效率大大上升,能仅用三步就算出sqrt。
    creamk寻找到这个数的过程至今令人匪夷所思,但即使是普渡大学的数学家Chris Lomont也没能找出效率比他高上多少的数字:
     普渡大学的数学家Chris Lomon在看了creamk的快速sqrt后觉得很有趣,决定要研究一下creamk弄出来的这个猜测值有什么奥秘。Lomont毕竟是一位数学家,在精心研究之后从理论上也推导出一个

          最佳猜测值,和creamk的数字非常接近, 0x5f37642f。Lomont计算出结果以后非常满意,于是拿自己计算出的起始值和creamk的神秘数字做比赛,看看谁的数字能够更快更精确的求得平方根。结果是creamk赢了。 谁也不知道creamk是怎么找到这个数字      的。

         最后Lomont发威了,采用暴力方法一个数字一个数字试过来,终于找到一个比creamk的数字效率高一些的数字,虽然实际上这两个数字所产生的结果非常近似,这个暴力得出的数字是0x5f375a86。

         Lomont为此写下一篇论文,"Fast Inverse Square Root"。

    在需要进行大数据量的sqrt运算时,creamk的qsqrt会比stl库中的 sqrt效率高出不知一星半点。

    所以当你觉得有必要用的时候,尽情的用它吧!

 
 
 
 

转载于:https://www.cnblogs.com/wujiechao/p/5042572.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值