首先,是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 及其原理的更多相关文章

  1. Volley 实现原理解析(转)

    Volley 实现原理解析 转自:http://blog.csdn.net/fengqiaoyebo2008/article/details/42963915 1. 功能介绍 1.1. Volley ...

  2. volley请求原理

    Volley 实现原理解析 本文为 Android 开源项目实现原理解析 中 Volley 部分 项目地址:Volley,分析的版本:35ce778,Demo 地址:Volley Demo 分析者:g ...

  3. 奇异值分解(SVD)原理与在降维中的应用

    奇异值分解(Singular Value Decomposition,以下简称SVD)是在机器学习领域广泛应用的算法,它不光可以用于降维算法中的特征分解,还可以用于推荐系统,以及自然语言处理等领域.是 ...

  4. node.js学习(三)简单的node程序&&模块简单使用&&commonJS规范&&深入理解模块原理

    一.一个简单的node程序 1.新建一个txt文件 2.修改后缀 修改之后会弹出这个,点击"是" 3.运行test.js 源文件 使用node.js运行之后的. 如果该路径下没有该 ...

  5. 线性判别分析LDA原理总结

    在主成分分析(PCA)原理总结中,我们对降维算法PCA做了总结.这里我们就对另外一种经典的降维方法线性判别分析(Linear Discriminant Analysis, 以下简称LDA)做一个总结. ...

  6. [原] KVM 虚拟化原理探究(1)— overview

    KVM 虚拟化原理探究- overview 标签(空格分隔): KVM 写在前面的话 本文不介绍kvm和qemu的基本安装操作,希望读者具有一定的KVM实践经验.同时希望借此系列博客,能够对KVM底层 ...

  7. H5单页面手势滑屏切换原理

    H5单页面手势滑屏切换是采用HTML5 触摸事件(Touch) 和 CSS3动画(Transform,Transition)来实现的,效果图如下所示,本文简单说一下其实现原理和主要思路. 1.实现原理 ...

  8. .NET Core中间件的注册和管道的构建(1)---- 注册和构建原理

    .NET Core中间件的注册和管道的构建(1)---- 注册和构建原理 0x00 问题的产生 管道是.NET Core中非常关键的一个概念,很多重要的组件都以中间件的形式存在,包括权限管理.会话管理 ...

  9. python自动化测试(2)-自动化基本技术原理

    python自动化测试(2) 自动化基本技术原理 1   概述 在之前的文章里面提到过:做自动化的首要本领就是要会 透过现象看本质 ,落实到实际的IT工作中就是 透过界面看数据. 掌握上面的这样的本领 ...

随机推荐

  1. 并查集入门--畅通工程(HDU1232)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1232 畅通工程 Time Limit: 4000/2000 MS (Java/Others)    M ...

  2. 总有你要的编程书单(GitHub )

    目录 IDE IntelliJ IDEA 简体中文专题教程 MySQL 21分钟MySQL入门教程 MySQL索引背后的数据结构及算法原理 NoSQL Disque 使用教程 Neo4j .rb 中文 ...

  3. spring boot 注解说明

    Starters 可以创建自己的Starter,但名字格式不能是 spring-boot-starter-*,而是 *-spring-boot-starter.类似Maven插件的规则.   自动配置 ...

  4. upupw注入by pass

    http:' and updatexml(null,concat(0x5c,(/*!00000select SCHEMA_name*/from/*!information_schema*/.schem ...

  5. Linux中断(interrupt)子系统之二:arch相关的硬件封装层【转】

    转自:http://blog.csdn.net/droidphone/article/details/7467436 Linux的通用中断子系统的一个设计原则就是把底层的硬件实现尽可能地隐藏起来,使得 ...

  6. sicily 1172. Queens, Knights and Pawns

    Description You all are familiar with the famous 8-queens problem which asks you to place 8 queens o ...

  7. swift中的如果在构造方法中使用KVC, 调用了super.init(), 报错, 基本数据类型属性找不到

    swift要求, 属性必须有初始化值, 如果不对其赋值, 可以加一个?系统会默认给其包装一个可选值(直说就是nil) 如果定义一个基本类型, 建议直接赋值, 不建议使用? 下面说下标题中的问题 有时候 ...

  8. [hadoop][会装]hadoop ha模式安装

    1.简介 2.X版本后namenode支持了HA特性,使得整个文件系统的可用性更加增强. 2.安装前提 zookeeper集群,zookeeper的安装参考[hadoop][会装]zookeeper安 ...

  9. Redis -- 过期时间 和 缓存 例子

    1.设置 key的生存时间,过期自动删除 exprire key  seconds    设置过期时间 秒数 ttl key   查询剩余时间 如果 设置了过期时间.对key进行 set 操作,会清除 ...

  10. linux删除乱码文件[转载]

    一些乱码文件不可以通过普通的rm命令进行管理.可以通过删除i节点的方式删除. [root@192_168_100_35 musicwap]# ls??,?K?k?ͨa*.?J]?k?Φ??P???Z? ...