码迷,mamicode.com
首页 > 其他好文 > 详细

cream 的qsqrt 及其原理

时间:2015-12-13 13:51:47      阅读:204      评论:0      收藏:0      [点我收藏+]

标签:

首先,是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效率高出不知一星半点。

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

 
 
 
 

cream 的qsqrt 及其原理

标签:

原文地址:http://www.cnblogs.com/wujiechao/p/5042572.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!