神奇的0x5f3759df

Quake-III Arena里面有一个闻名游戏界的开平方取倒函数:

复制代码
/*
** float q_rsqrt( float number )
*/
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;
}
复制代码

第一次看到感觉很厉害,但却无法弄懂它的原理。这个函数的作用是用于对一个数开平方并取倒数,比用C库的sqrt实现(1.0f/sqrt(x))快了将近4倍。实现原理是牛顿迭代,也是平方根的一般算法,反复执行 y = y * ( threehalfs – ( x2 * y * y ) ); 其中y趋向于(1.0f/sqrt(x)),拿到的结果可以无限接近于我们想要的精度。

这个函数实现的算法被称为‘Fast Inverse Square Root’, 而它神奇的地方在于函数里面的实现采用了一个神秘的常数:0x5f3759df. 这个常数的来源目前无法被考究,也不能追溯确定这个常数的方法。

这里还有个典故,在Q3的代码公布,并且数学家Chris Lomont得知0x5f3759df这个常数之后,他通过用暴力搜索得出了与0x5f3759df非常接近、并且代入后得出的结果更加精确的魔数0x5f375a86,当然,实际上和0x5f3759df还是非常接近。

3D游戏引擎设计的作者David Eberly曾经发表论文解释了这个算法:
http://www.geometrictools.com/Documentation/FastInverseSqrt.pdf

不过最早还是Lomont在2003发表的:
http://www.lomont.org/Math/Papers/2003/InvSqrt.pdf

而David Eberly最近的一次补充是在2010年。

See also: http://en.wikipedia.org/wiki/Fast_inverse_square_root

posted @   CodeMIRACLE  阅读(2216)  评论(0编辑  收藏  举报
编辑推荐:
· ASP.NET Core - 日志记录系统(二)
· .NET 依赖注入中的 Captive Dependency
· .NET Core 对象分配(Alloc)底层原理浅谈
· 聊一聊 C#异步 任务延续的三种底层玩法
· 敏捷开发:如何高效开每日站会
阅读排行:
· 终于决定:把自己家的能源管理系统开源了!
· 互联网不景气了那就玩玩嵌入式吧,用纯.NET开发并制作一个智能桌面机器人(一):从.NET IoT入
· C#实现 Winform 程序在系统托盘显示图标 & 开机自启动
· ASP.NET Core - 日志记录系统(二)
· 实现windows下简单的自动化窗口管理
点击右上角即可分享
微信分享提示