sqrt函数实现之卡马克方法

sqrt函数的实现主要有三种方式:

  1. 二分法
  2. 牛顿法
  3. 卡马克方法

这里主要介绍高效的卡马克方法。卡马克方法起源于《雷神之锤III竞技场》中使用的平方根倒数速算法,下列代码是平方根倒数速算法在《雷神之锤III竞技场》源代码中的应用实例。示例剥离了C语言预处理器的指令,但附上了原有的注释:

float Q_rsqrt( float number )
{
    long i;
    float x2, y;
    const float threehalfs = 1.5F;

    x2 = number * 0.5F;
    y  = number;
    i  = * ( long * ) &y;// evil floating point bit level hacking
    i  = 0x5f3759df - ( i >> 1 );               // what the fuck?
    y  = * ( float * ) &i;
    y  = y * ( threehalfs - ( x2 * y * y ) );   // 1st iteration
//  y  = y * ( threehalfs - ( x2 * y * y ) );   // 2nd iteration, this can be removed

    return y;
}

为计算平方根倒数的值,软件首先要先确定一个近似值,而后则使用某些数值方法不断计算修改近似值,直至达到可接受的精度。在1990年代初(也即该算法发明的大概时间),软件开发时通用的平方根算法多是从查找表中获取近似值,而这段代码取近似值耗时比之更短,达到精确度要求的速度也比通常使用的浮点除法计算法快四倍,虽然此算法会损失一些精度,但性能上的巨大优势已足以补偿损失的精度。由代码中对原数据的变量类型声明为float可看出,这一算法是针对IEEE 754标准格式的32位浮点数设计的,不过据Chris Lomont和后来的Charles McEniry的研究看,这一算法亦可套用于其他类型的浮点数上。

平方根倒数速算法在速度上的优势源自将浮点数转化为长整型以作整数看待,并用特定常数0x5f3759df与之相减。然而对于代码阅读者来说,他们却难以立即领悟出使用这一常数的目的,因此和其它在代码中出现的难以理解的常数一样,这一常数亦被称为“魔术数字”。如此将浮点数当作整数先位移后减法,所得的浮点数结果即是对输入数字的平方根倒数的粗略估计值,而后再进行一次牛顿迭代法,以使之更精确后,代码即执行完毕。由于算法所生成的用于输入牛顿法的首次近似值已经相当精确,此算法所得近似值的精度已可接受,而若使用与《雷神之锤III竞技场》同为1999年发布的Pentium III中的SSE指令rsqrtss计算,则计算平方根倒数的收敛速度更慢,精度也更低。

要理解这段代码,首先需了解浮点数的存储格式。一个浮点数以32个二进制位表示一个有理数,而这32位由其意义分为三段:首先首位为符号位,如若是0则为正数,反之为负数;接下来的8位表示经过偏移处理(这是为了使之能表示-127-128)后的指数;最后23位表示的则是有效数字中除最高位以外的其余数字。将上述结构表示成公式即为,其中{\displaystyle \scriptstyle m}表示有效数字的尾数(此处{\displaystyle \scriptstyle 0\leq m<1},偏移量{\displaystyle \scriptstyle B=127}[文 10],而指数的值{\displaystyle \scriptstyle E-B}决定了有效数字(在Lomont和McEniry的论文中称为“尾数”(mantissa))代表的是小数还是整数[文 11]。以上图为例,将描述带入有{\displaystyle \scriptstyle m=1\times 2^{-2}=0.250}),且{\displaystyle \scriptstyle E-B=124-127=-3},则可得其表示的浮点数为{\displaystyle \scriptstyle x=(1+0.250)\cdot 2^{-3}=0.15625}

原文地址:https://www.cnblogs.com/muyangshaonian/p/9649599.html

时间: 2024-11-08 22:24:07

sqrt函数实现之卡马克方法的相关文章

平方根倒数速算法(卡马克开方法)

平方根倒数速算法(Fast inverse square root),经常和一个十六进制的常量 0x5f3759df联系起来.该算法被用来快速运算平方根倒数,速度是 float(1/sqrt(x)) 方法的4倍.该算法大概由上个世纪90年代的硅图公司开发出来,后来出现在John Carmark的Quake III Arena的源码中. 这是一个古老的算法,最早的讨论见于2001年中国的CSDN论坛上.并且该段代码可能已经不适用于当代的64bits机器,因为现在的64bits的机器上 long 型

一个Sqrt函数引发的血案

我们平时经常会有一些数据运算的操作,需要调用sqrt,exp,abs等函数,那么时候你有没有想过:这个些函数系统是如何实现的?就拿最常用的sqrt函数来说吧,系统怎么来实现这个经常调用的函数呢? 虽然有可能你平时没有想过这个问题,不过正所谓是"临阵磨枪,不快也光",你"眉头一皱,计上心来",这个不是太简单了嘛,用二分的方法,在一个区间中,每次拿中间数的平方来试验,如果大了,就再试左区间的中间数:如果小了,就再拿右区间的中间数来试.比如求sqrt(16)的结果,你先试

【转载】一个Sqrt函数引发的血案

转自:http://www.cnblogs.com/pkuoliver/archive/2010/10/06/sotry-about-sqrt.html 源码下载地址:http://diducoder.com/sotry-about-sqrt.html 好吧,我承认我标题党了,不过既然你来了,就认真看下去吧,保证你有收获. 我们平时经常会有一些数据运算的操作,需要调用sqrt,exp,abs等函数,那么时候你有没有想过:这个些函数系统是如何实现的?就拿最常用的sqrt函数来说吧,系统怎么来实现这

卡马克算法(地图重复利用,跑酷类游戏)

----------------------------下面是理论知识-------------------------- 卡马克算法:由约翰·卡马克(John Carmack)开发的一种游戏地图处理方法,被广泛运用到2D卷轴式游戏和手机游戏中.约翰·卡马克:id Software创始人之一,技术总监.享誉世界的著名程序员,以卡马克算法和3D游戏引擎开发而闻名世界,被奉为游戏行业偶像.同时他也是个全面型的技术天才,现在致力于民用航天器开发,是民用航天器开发小组Armadillo Aerospac

卡马克卷轴算法研究

对于J2ME框架下的手机游戏程序的开发,其地图滚动的重绘有多种算法,由于手机性能的限制和开发周期等其他非技术条件,需要根据情况灵活选择所需的技术.但在及其苛刻条件下,如系统CPU资源不足,地图块尺寸较小等,会造成屏幕闪耀,帧数过低等情况,严重影响到游戏体验.在开发中如此类问题无法绕过以及避免(指通过修改策划方案,以及程序使用的技术框架),则需要考虑使用地图缓冲绘制技术,卡马克卷轴就是一种最经典的地图缓冲绘制技术.可有效的改善在地图绘制中的屏幕闪耀,帧数过低等情况. English Abstrac

关于sqrt函数的算法

我们平时经常会有一些数据运算的操作,需要调用sqrt,exp,abs等函数,那么时候你有没有想过:这个些函数系统是如何实现的?就拿最常用的sqrt函数来说吧,系统怎么来实现这个经常调用的函数呢? 虽然有可能你平时没有想过这个问题,不过正所谓是“临阵磨枪,不快也光”,你“眉头一皱,计上心来”,这个不是太简单了嘛,用二分的方法,在一个区间中,每次拿中间数的平方来试验,如果大了,就再试左区间的中间数:如果小了,就再拿右区间的中间数来试.比如求sqrt(16)的结果,你先试(0+16)/2=8,8*8=

Windows中openProcess函数返回ERROR_ACCESS_DENIED的解决方法

辛辛苦苦开始了创业,好不容易见到了天使投资人,如何去打动明星投资人?如何能拿到那一笔"救命"钱?看徐小平.雷军这样说. 1. 天使投资人偏爱投什么样的创业者? 雷军:你有强烈的渴望做成一件伟大的事情,并且能让投资者相信你能做得成这件事情.掏自己的钱创业是创业成功率最高的一种,因为在那一瞬间你重视了,你花的每一分钱都是自己的血汗钱和别人的血汗钱,不会轻松把别的投资人的钱打水漂. 曾李青:我们体系内投了好几家公司,发现我们投资成功的公司要么是有做大公司的成功经验,要么是名校毕业.好学校不一

安卓模拟器创建和使用SD卡的方法

安卓模拟器创建和使用SD卡的方法: 创建一个SD卡镜像文件 打开cmd,进入Android SDK安装路径下的tools目录下,输入如下命令:mksdcard 1024M sdcard.img 该命令会在当前目录下生成一个sdcard.img文件,该文件是Android模拟器的SD卡镜像文件.1024M表示SD卡有1024M大小,即1G容量.目前Android支持8M~128G的SD卡. 运行带有SD卡的模拟器 创建了SD卡镜像文件,只是创建了一个文件,还不能在模拟器中直接使用,要在模拟器加载该

函数指针与函数指针数组的使用方法

转自:http://blog.csdn.net/feitianxuxue/article/details/7300291 函数指针与函数指针数组的使用方法 函数指针: 函数指针包含函数在内存中的地址.数组名实际上就是数组的第一个元素在内存中的地址,类似地,函数名实际上也是执行这个函数任务的代码在内存中的起始地址. 函数指针可以传递给函数.从函数返回.保存在数组中.赋予另一个函数指针或者调用底层函数. 下面我们用数值算法accumulate讨论下函数指针的用法.accumulate是一种常用的ST