您的位置:首页 > 其它

Quake3 快速开平方和开平方倒数计算优化

2016-02-23 08:46 399 查看
在Quake3中,卡马克使用了广为人知的魔数来优化,开平方和开平方倒数计算。而在Doom3中改为查表计算了。

[cpp] view
plain copy







/*

================

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;

}

[cpp] view
plain copy







/*

** 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

return y;

}

开平方和开平方倒数的算法是一样,都使用了魔数0x5f3759df,利用牛顿迭代法进行迭代。只是在上面的迭代中,开平方迭代了2次,开平方倒数迭代了1次。开平方最后结果,是开平方倒数在乘以原数值的结果。在GameDev.net上有人做过测试,该函数的相对误差约为0.177585%,速度比C标准库的sqrt提高超过20%。如果增加一次迭代过程,相对误差可以降低到e-004 的级数,但速度也会降到和sqrt差不多。

下面对这2个算法进行微量的优化。

利用union去除float类型的强转,和一些赋值操作
long类型改用int类型
把中间变量的赋值操作去除,替换到计算式中

[cpp] view
plain copy







static float InvSqrtf(float x)

{

union

{

float x;

int i;

} u;

u.x = x;

u.i = 0x5f3759df - (u.i >> 1);

return u.x * (1.5f - 0.5f * x * u.x * u.x);

}

static float Sqrtf(float x)

{

union

{

float x;

int i;

} u;

u.x = x;

u.i = 0x5f3759df - (u.i >> 1);

// InvSqrt(x) * x, equal Sqrt(x)

return u.x * (1.5f - 0.5f * x * u.x * u.x) * x;

}

如果,精度不够可以增加迭代次数,不过也会降低性能。经过测试精度还不错。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: