首先,是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. Vue 使用中的小技巧(山东数漫江湖)

    在vue的使用过程中会遇到各种场景,当普通使用时觉得没什么,但是或许优化一下可以更高效更优美的进行开发.下面有一些我在日常开发的时候用到的小技巧,在下将不定期更新~ 1. 多图表resize事件去中心 ...

  2. 实现拷贝函数(strcpy)

    #include <stdio.h> #include <stdlib.h> // 函数声明 char *mystrcpy(char *object, char *source ...

  3. HDU 4757 可持久化trie树

    首先如果给定一些数,询问这些数中哪个数^给定的数的值最大的话,我们可以建立一颗trie树,根连接的两条边分别为0,1,表示二进制下第15位,那么我们可以建立一颗trie树,每一条从根到叶子节点的链表示 ...

  4. Python模块学习 - ConfigParser

    配置文件 很多软件都用到了配置文件,像git运行的时候会读取~/gitconfig,MySQL运行的时候会读取/etc/my.cnf,Python 提供的包管理工具pip命令,也会去读取~/.pip/ ...

  5. ThinkPHP5 正则验证中有“|”时提示“规则错误”的解决方案

    正则规则中有“|”时,会引起解析错误: 'regex:\d{3,4}[\s,-]?\d{7,8}|1[3,4,5,8]\d[\s,-]?\d{4}[\s,-]?\d{4}' 使用数组语法可以解决: [ ...

  6. openssl-0.9.8y

    openssl-0.9.8y 支持 32位和64位 编译不报错和向上兼容和向下兼容. http://www.openssl.org/source/openssl-0.9.8y.tar.gz https ...

  7. [转] Socket心跳包异常检测的C语言实现,服务器与客户端代码案例

    转载自:zxh2075的专栏 在Socket心跳机制中,心跳包可以由服务器发送给客户端,也可以由客户端发送给服务器,不过比较起来,前者开销可能较大.本文实现的是由客户端给服务器发送心跳包,服务器不必返 ...

  8. jps命令学习

    jps命令学习 标签(空格分隔): jvm jps介绍 ( JVM Process Status Tool ) 网文 jps命令用于查看当前Java进程及其pid等相关信息,同ps -ef | gre ...

  9. C入门之一

    1.stdio.h不要写错成studio.h 2. #include <stdio.h> int main() { /* 我的第一个 C 程序 */ printf("Hello, ...

  10. 兼容python3的SSDB客户端

    SSDB.py import socket class SSDB_Response(object): def __init__(self, code='', data_or_message=None) ...