免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 5674 | 回复: 6

[函数] [转]Quake-III代码里神奇的浮点开方函数 [复制链接]

论坛徽章:
0
发表于 2007-06-23 23:33 |显示全部楼层
http://game.chinaitlab.com/devdoc/723647.html

    Quake-III Arena (雷神之锤3)是我大学时期爱玩的经典游戏之一。喜爱这个系列的游戏,不仅因为画面和内容,更重要的是我得计算计配置低,但Q3A却能极其流畅地运行。这要归功于它3D引擎的开发者约翰-卡马克(John Carmack)。事实上早在90年代初DOS时代,只要能在PC上搞个小动画都能让人惊叹一番的时候,John Carmack就推出了石破天惊的Castle Wolfstein, 然后再接再励,doom, doomII, Quake……每次都把3-D技术推到极致。他的3D引擎代码资极度高效,几乎是在压榨PC机的每条运算指令。当初MS的Direct3D也得听取他的意见,修改了不少API.最近,QUAKE的开发商ID software 遵守GPL协议,公开了QUAKE-III的原代码,让世人有幸目睹Carmack传奇的3D引擎的原码。
 
  这是QUAKE-III原代码的下载地址:http://www.chinagamedev.net/showtopic-461.aspx我们知道,越底层的函数,调用越频繁。3D引擎归根到底还是数学运算。那么找到最底层的数学运算函数(在game/code/q_math.c), 必然是精心编写的。里面有很多有趣的函数,很多都令人惊奇,估计我们几年时间都学不完。
 
  最令人惊讶的是平方根函数sqrt()。课本里说的,基本上是牛顿跌代法,通过若干步的叠代,结果越来越接近真实结果。

 但q_math.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;        // 浮点数按BIT强行赋给长整形
  i  = 0x5f3759df - ( i >> 1 ); // 没天理!!!!!
  y  = * ( float * ) &i;
  y  = y * ( threehalfs - ( x2 * y * y ) ); // 第1次叠代
  // y  = y * ( threehalfs - ( x2 * y * y ) ); // 第2次叠代,可以删除
  #ifndef Q3_VM
  #ifdef __linux__
    assert( !isnan(y) ); // bk010122 - FPE?
  #endif
  #endif
  return y;
}
      函数返回1/sqrt(x),这个函数在图像处理中比sqrt(x)更有用。
       注意到这个函数只用了一次叠代!(其实就是根本没用叠代,直接运算)。编译,实验,这个函数不仅工作的很好,而且比标准的sqrt()函数快4倍!要知道,编译器自带的函数,可是经过严格仔细的汇编优化的啊!

      这个简洁的函数,最核心,也是最让人费解的,就是标注了“没天理”那句:(原代码的注释是 what the fu*ck ?)
    i  = 0x5f3759df - ( i >> 1 ); // 没天理!!!!!

       再加上y  = y * ( threehalfs - ( x2 * y * y ) );
两句话就完成了开方运算!而且注意到,核心那句是定点移位运算,速度极快!特别在很多没有乘法指令的RISC结构CPU上,这样做是极其高效的。

       最让人感兴趣的,是那个常数0x5f3759df。我的猜测是这样的:牛顿叠代法用1/2作为初始点进行N步叠代得到精确结果。这里计算一个最佳猜测值 i,然后,以i为起始点,只需要做1步叠代,就可以得到相当精确的结果。如果做2次叠代,就更为精确了(屏蔽掉那句)。

......................(略)

不知各位高手对那个函数怎么看

论坛徽章:
0
发表于 2007-06-23 23:40 |显示全部楼层
看看这篇文档
http://www.lomont.org/Math/Papers/2003/InvSqrt.pdf

我下载的原始代码是这样的

  1. #if !idppc
  2. /*
  3. ** float q_rsqrt( float number )
  4. */
  5. float Q_rsqrt( float number )
  6. {
  7.         long i;
  8.         float x2, y;
  9.         const float threehalfs = 1.5F;

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

  17. #ifndef Q3_VM
  18. #ifdef __linux__
  19.         assert( !isnan(y) ); // bk010122 - FPE?
  20. #endif
  21. #endif
  22.         return y;
  23. }

  24. float Q_fabs( float f ) {
  25.         int tmp = * ( int * ) &f;
  26.         tmp &= 0x7FFFFFFF;
  27.         return * ( float * ) &tmp;
  28. }
  29. #endif
复制代码

[ 本帖最后由 antonym55 于 2007-6-23 23:50 编辑 ]

论坛徽章:
0
发表于 2007-06-23 23:42 |显示全部楼层
>> 0x5f3759df - ( i >> 1 );

这个常数估计是做类型转换的优化而用的,可以看看浮点数方面的优化资料来了解了解。

论坛徽章:
0
发表于 2007-06-24 01:20 |显示全部楼层
这个是非常猛的fu*ck东东,狂赞

论坛徽章:
0
发表于 2007-06-24 02:20 |显示全部楼层
我来膜拜了

论坛徽章:
0
发表于 2007-06-24 12:51 |显示全部楼层
十分感谢二楼 antonym55 提供的pdf文件!!
  能透露一下是在那里找到这类资料的么?

论坛徽章:
26
处女座
日期:2016-04-18 14:00:4515-16赛季CBA联赛之深圳
日期:2020-06-02 10:10:5015-16赛季CBA联赛之广夏
日期:2019-07-23 16:59:452016科比退役纪念章
日期:2019-06-26 16:59:1315-16赛季CBA联赛之天津
日期:2019-05-28 14:25:1915-16赛季CBA联赛之青岛
日期:2019-05-16 10:14:082016科比退役纪念章
日期:2019-01-11 14:44:062016科比退役纪念章
日期:2018-07-18 16:17:4015-16赛季CBA联赛之上海
日期:2017-08-22 18:18:5515-16赛季CBA联赛之江苏
日期:2017-08-04 17:00:4715-16赛季CBA联赛之佛山
日期:2017-02-20 18:21:1315-16赛季CBA联赛之天津
日期:2016-12-12 10:44:23
发表于 2007-06-24 14:10 |显示全部楼层
原帖由 antonym55 于 2007-6-23 23:40 发表
// what the fuck?


偶的翻译 : 操 ,这是什么?
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP