旧闻一则:神秘的0x5f3759df 不可思议的Quake III源码
icon2 Program Impossible | icon4 2007-11-24 19:51| icon38 Comments | 本文内容遵从CC版权协议 转载请注明出自matrix67.com

    Quake III公开源码后,有人在game/code/q_math.c里发现了这样一段代码。它的作用是将一个数开平方并取倒,经测试这段代码比(float)(1.0/sqrt(x))快4倍:
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

  #ifndef Q3_VM
  #ifdef __linux__
    assert( !isnan(y) ); // bk010122 - FPE?
  #endif
  #endif
  return y;
}


    code/common/cm_trace.c中也出现了这样一段解释sqrt(x)的函数,与上面的代码唯一不同的就是这个函数返回的是number*y:
/*
================
SquareRootFloat
================
*/
float SquareRootFloat(float number) {
    long i;
    float x, y;
    const float f = 1.5F;

    x = number * 0.5F;
    y  = number;
    i  = * ( long * ) &y;
    i  = 0x5f3759df - ( i >> 1 );
    y  = * ( float * ) &i;
    y  = y * ( f - ( x * y * y ) );
    y  = y * ( f - ( x * y * y ) );
    return number * y;
}


    这样的代码速度肯定飞快,我就不用多说了;但算法的原理是什么呢?其实说穿了也不是很神,程序首先猜测了一个接近1/sqrt(number)的值,然后两次使用牛顿迭代法进行迭代。根号a的倒数实际上就是方程1/x^2 - a = 0的一个正实根,它的导数是-2/x^3。运用牛顿迭代公式x' = x - f(x)/f'(x),式子化简为x' = x * (1.5 - 0.5a * x^2)。迭代几次后,x的值将趋于1/sqrt(a)。
    但这段代码真正牛B的是那个神秘的0x5f3759df,因为0x5f3759df - (i >> 1)出人意料地接近根号y的倒数。人们都不知道这个神秘的常数是怎么来的,只能把它当作神来膜拜。这个富有传奇色彩的常数到底咋回事,很少有人说得清楚。这篇论文比较科学地解释了这个常数。

8 条回复

  • 楼层: 沙发 | | yiyi 说:

    sofa~

  • 楼层: 板凳 | | dpupet 说:

    我来抢板凳,Matrix牛还没有回复我的问题呢,[sad],乘法口诀后的留言。

  • 楼层: 地毯 | | x2studio 说:

    呃。0x5f375a86似乎更厉害呢。

  • 楼层: 地板 | | Freeze 说:

    (1.0/sqrt(x)
    括号不匹配……

    回复:谢谢指正,已改正

  • 楼层: 地下室 | | dahe_1984 说:

    Q_rsqrt(4)=0.499154;
    1.0/sqrt(4)=0.500000。不知道对精度是怎么看待的?

  • 楼层: 地基 | | deoxyz 说:

    回ls...0.1%的精度对于quake3完全够用,毕竟只是求一个向量正交化
    另外我把那篇文章翻译了一下
    http://www.seraphy.cn/blog/article.asp?id=17
    最后面有pdf格式下载
    有兴趣去看一下吧

  • 楼层: 地壳 | | 闲耘 说:

    有趣,又迷上数学了。
    另外,似乎有另一种防垃圾评论的方式,就是判断内容里的链接数量和连续的评论内容相似度。刚刚不知道是因为数学不好,还是超时而被拒绝了。[lol]

  • 楼层: 地幔 | | TX 说:

    您好。看了几篇文章,很有启发!尤其是位运算的。

    我有点疑问?是怎么样判断代码的执行效率的呢?几倍或是什么的?
    有什么工具,或者是?

    抱歉,本人新来乍到,还在为Noip奋斗着……
    能否请教,针对Noip,或者根高,该怎么样提高呢?

您也随便说几句吧:

请注意:如果您是第一次在本站发表评论,您的评论需要通过管理员的审核。

您可以在Gravatar设置您的头像。