??xml version="1.0" encoding="utf-8" standalone="yes"?>国产精品伦理一区二区,精品少妇一区二区三区视频免付费 ,国产黄在线观看免费观看不卡http://www.aygfsteel.com/Titan/articles/31415.htmlTitanTitanSat, 18 Feb 2006 13:05:00 GMThttp://www.aygfsteel.com/Titan/articles/31415.htmlhttp://www.aygfsteel.com/Titan/comments/31415.htmlhttp://www.aygfsteel.com/Titan/articles/31415.html#Feedback0http://www.aygfsteel.com/Titan/comments/commentRss/31415.htmlhttp://www.aygfsteel.com/Titan/services/trackbacks/31415.html?D囑Ş~程中,l常要求qxҎqx根的倒数Q例如:求向量的长度或将向量归一化。C数学函数库中?STRONG>sqrth理想的精度,但对?D游戏E式来说速度太慢。我们希望能够在保证_的精度的同时Q进一步提高速度?/P>

Carmack?STRONG>QUAKE3中用了下面的算法,它第一ơ在公众场合出现的时候,几乎震住了所有的人。据说该法其实q不是Carmack发明的,它真正的作者是Nvidia?STRONG>Gary TarolliQ未l证实)?/P>

//
// 计算参数x的^Ҏ的倒数
//
float InvSqrt (float x)
{
	float xhalf = 0.5f*x;
	int i = *(int*)&x;
	i = 0x5f3759df - (i >> 1);	// 计算W一个近似根
	x = *(float*)&i;
	x = x*(1.5f - xhalf*x*x);	// 牛顿q代?
	return x;
}

该算法的本质其实是牛顿q代?/STRONG>QNewton-Raphson MethodQ简UNRQ,而NR的基则是泰勒U数QTaylor SeriesQ。NR是一U求方程的近似根的方法。首先要估计一个与方程的根比较靠近的数|然后Ҏ公式推算下一个更加近似的数|不断重复直到可以获得满意的精度。其公式如下Q?

函数Qy=f(x)

其一阶导CؓQy'=f'(x)

则方E:f(x)=0 的第n+1个近似根?

x[n+1] = x[n] - f(x[n]) / f'(x[n])
NR最关键的地方在于估计第一个近似根。如果该q似根与真根_靠近的话Q那么只需要少数几ơP代,可以得到满意的解?

现在回过头来看看如何利用牛顿法来解决我们的问题。求qx根的倒数Q实际就是求方程1/(x^2)-a=0的解。将该方E按牛顿q代法的公式展开为:

x[n+1]=1/2*x[n]*(3-a*x[n]*x[n])
?/2攑ֈ括号里面Q就得到了上面那个函数的倒数W二行?

接着Q我们要设法估计W一个近似根。这也是上面的函数最奇的地斏V它通过某种Ҏ出了一个与真根非常接近的近似根Q因此它只需要用一ơP代过E就获得了较满意的解。它是怎样做到的呢Q所有的奥妙在于这一行:

i = 0x5f3759df - (i >> 1);	// 计算W一个近似根

莫名其妙的语句,不是吗?但仔l想一下的话,q是可以理解的。我们知道,IEEE标准下,floatcd的数据在32位系l上是这栯C的Q大体来说就是这P但省略了很多l节Q有兴趣可以GOOGLEQ:

bitsQ?1 30 ... 0
31Q符号位
30-23Q共8位,保存指数QEQ?
22-0Q共23位,保存数QMQ?

所以,32位的点数用十进制实数表C就是:M*2^E。开根然后倒数是QM^(-1/2)*2^(-E/2)。现在就十分清晰了。语句i>>1其工作就是将指数除以2Q实?^(E/2)的部分。而前面用一个常数减dQ目的就是得到M^(1/2)同时反{所有指数的W号?/P>

至于那个0x5f3759dfQ呃Q我只能_的确是一个超U的Magic Number?/P>

那个Magic Number是可以推导出来的Q但我ƈ不打在q里讨论Q因为实在太J琐了。简单来_其原理如下:因ؓIEEE的QҎ中,数M省略了最前面?Q所以实际的数?+M。如果你在大学上数学课没有打瞌睡的话Q那么当你看?1+M)^(-1/2)q样的Ş式时Q应该会马上联想的到它的泰勒U数展开Q而该展开式的W一就是常数。下面给出简单的推导q程Q?/P>

对于实数R>0Q假讑օ在IEEE的Q点表CZQ?
指数为EQ尾CؓMQ则Q?

R^(-1/2)
= (1+M)^(-1/2) * 2^(-E/2)

?1+M)^(-1/2)按泰勒数展开Q取W一,得:

原式
= (1-M/2) * 2^(-E/2)
= 2^(-E/2) - (M/2) * 2^(-E/2)

如果不考虑指数的符L话,
(M/2)*2^(E/2)正是(R>>1)Q?
而在IEEE表示中,指数的符号只需单地加上一个偏Ud可,
而式子的前半部分刚好是个常数Q所以原式可以{化ؓQ?

原式 = C - (M/2)*2^(E/2) = C - (R>>1)Q其中C为常?

所以只需要解方程Q?
R^(-1/2)
= (1+M)^(-1/2) * 2^(-E/2)
= C - (R>>1)
求出令到相对误差最的C值就可以?

上面的推DE只是我个h的理解,q未得到证实。而Chris Lomont则在他的论文中详l讨Z最后那个方E的解法Qƈ试在实际的机器上寻找最佳的常数C。有兴趣的朋友可以在文末扑ֈ他的论文的链接?/P>

所以,所谓的Magic NumberQƈ不是从N元宇宙的某个星系׃时空扭曲而掉到地球上的,而是几百q前有的数学理论。只要熟悉NR和泰勒敎ͼ你我同样有能力作出类似的优化?/P>

?A >GameDev.net上有人做q测试,该函数的相对误差Uؓ0.177585%Q速度比C标准库的sqrt提高过20%。如果增加一ơP代过E,相对误差可以降低到e-004的敎ͼ但速度也会降到和sqrt差不多。据说在DOOM3中,Carmack通过查找表进一步优化了该算法,_ֺq乎完美Q而且速度也比原版提高了一截(正在努力弄源码,谁有发我一份)?/P>

值得注意的是Q在Chris Lomont的演中Q理Z最优秀的常敎ͼ_ֺ最高)?STRONG>0x5f37642fQƈ且在实际试中,如果只用一ơP代的话,其效果也是最好的。但奇怪的是,l过两次NR后,在该常数下解的精度将降低得非常厉宻I天知道是怎么回事Q)。经q实际的试Q?STRONG>Chris Lomont认ؓQ最优秀的常数是0x5f375a86。如果换?4位的double版本的话Q算法还是一LQ而最优常数则?STRONG>0x5fe6ec85e7de30daQ又一个o人冒汗的Magic Number - -bQ?/P>

q个法依赖于QҎ的内部表C和字节序Q所以是不具UL性的。如果放到Mac上跑׃挂掉。如果想具备可移植性,q是乖乖用sqrt好了。但法思想是通用的。大家可以尝试推一下相应的qx根算法?/P>

下面l出Carmack在QUAKE3中用的qx根算法。Carmack已经QUAKE3的所有源代码捐给开源了Q所以大家可以放心用,不用担心会收到律师信?/P>

//
// Carmack在QUAKE3中用的计算qx根的函数
//
float CarmSqrt(float x){
	union{
		int intPart;
		float floatPart;
	} convertor;
	union{
		int intPart;
		float floatPart;
	} convertor2;
	convertor.floatPart = x;
	convertor2.floatPart = x;
	convertor.intPart = 0x1FBCF800 + (convertor.intPart >> 1);
	convertor2.intPart = 0x5f3759df - (convertor2.intPart >> 1);
	return 0.5f*(convertor.floatPart + (x * convertor2.floatPart));
}

另一个基于同L法的更高速度的sqrt实现如下。其只是单地指数除?Qƈ没有考虑数的方栏V要看懂该代码的话必ȝ道,在IEEE点数的格式中,E是由实际的指数加127得到的。例如,如果实数?.1234*2^10Q在点表示中,EQ第23-30位)的值其实ؓ10+127=137。所以下面的代码中,要处?27偏移Q这是常数0x3f800000的作用。我没实际测试过该函敎ͼ所以对其优劣无从评论,但估计其_ֺ应该会降低很多?/P>

float	Faster_Sqrtf(float f)
{
	float	result;
	_asm
	{
		mov eax, f
		sub eax, 0x3f800000
		sar eax, 1
		add eax, 0x3f800000
		mov result, eax
	}
	return result;
}

除了ZNR的方法外Q其他常见的快速算法还?STRONG>多项式D。下面的函数取自?D游戏~程大师技巧》,它用一个多式来近似替代原来的长度方程Q但我搞不清楚作者用的公式是怎么推导出来的(如果你知道的话请告诉我,谢谢Q?/P>

//
// 	q个函数计算?0,0)?x,y)的距,相对误差?.5%
//
int FastDistance2D(int x, int y)
{
	x = abs(x);
	y = abs(y);
	int mn = MIN(x,y);
	return(x+y-(mn>>1)-(mn>>2)+(mn>>4));
}
//
// 该函数计?0,0,0)?x,y,z)的距,相对误差?%
//
float FastDistance3D(float fx, float fy, float fz)
{
	int temp;
	int x,y,z;
	// 保所有的gؓ?
	x = int(fabs(fx) * 1024);
	y = int(fabs(fy) * 1024);
	z = int(fabs(fz) * 1024);
	// 排序
	if (y < x) SWAP(x,y,temp)
	if (z < y) SWAP(y,z,temp)
	if (y < x) SWAP(x,y,temp)
	int dist = (z + 11 * (y >> 5) + (x >> 2) );
	return((float)(dist >> 10));
}

q有一U方法称?STRONG>Distance EstimatesQ距评伎ͼQ,如下图所C:

U线所描绘的正八边形上的点为:
octagon(x,y) = min((1/?) * (|x|+|y|), max(|x|,|y|))
求出向量v1和v2的长度,则:
?x^2+y^2) = (|v1|+|v2|)/2 * octagon(x,y)

到目前ؓ止我们都在讨论QҎ的方根算法,接下来轮到整数的Ҏ法。也许有为对整型数据求方ҎM意义Q因Z得到cM99^(1/2)=9的结果。通常情况下确实是q样Q但当我们用定Ҏ的时候(定点C然被应用在很多系l上面,例如d堂的GBA之类的手持设备)Q整数的Ҏ法显得非帔R要。对整数开qx的算法如下。我q不打算在这讨论它(事实是我也没有仔l考究Q因为在短期内都不会用到- -bQ,但你可以在文?STRONG>James Ulery的论文中扑ֈ非常详细的推DE?/P>

//
// Z阅读的需要,我在下面的宏定义中添加了换行W?
//
#define step(shift)
if((0x40000000l >> shift) + sqrtVal <= val)
{
	val -= (0x40000000l >> shift) + sqrtVal;
	sqrtVal = (sqrtVal >> 1) | (0x40000000l >> shift);
}
else
{
	sqrtVal = sqrtVal >> 1;
}
//
// 计算32位整数的qx?
//
int32 xxgluSqrtFx(int32 val)
{
	// Note: This fast square root function
	// only works with an even Q_FACTOR
	int32 sqrtVal = 0;
	step(0);
	step(2);
	step(4);
	step(6);
	step(8);
	step(10);
	step(12);
	step(14);
	step(16);
	step(18);
	step(20);
	step(22);
	step(24);
	step(26);
	step(28);
	step(30);
	if(sqrtVal < val)
	{
		++sqrtVal;
	}
	sqrtVal <<= (Q_FACTOR)/2;
	return(sqrtVal);
}

关于sqrt的话题早?003q便已在 GameDev.net上得Cq泛的讨论(可见我实在非常火星了Q当然不排除q有其他在冥王星的人,嘿嘿Q。而尝试探I该话题则完全是Z本h的兴和好奇心(换句话说是无知Q。其实现在随着FPU的提升和对向量运的g支持Q大部分pȝ上都提供了快速的sqrt实现。如果是处理大批量的向量的话Q据说最快的Ҏ是用SIMDQ据说而已Q我压根不懂Q,可同步计?个向量?/P>


相关资源

q里是当q在GameDev.net?A >讨论Q有的东西包括一些高手的评论和几个版本的sqrt的实数倹{?/P>

有关NR和泰勒数的内容Q请参见MathWorld?/P>

q有两篇论文。一是关于Carmack法的推DE;另一是关于整数Ҏ法的推DE:

以上观点仅代表我个h看法Q由于水qx限,如有错漏Q还望指正。此外,如果你有M看法或意见的话,Ƣ迎?A >论坛留言或者给我发E-MailQ?STRONG>wang_yong_cong@msn.com?/P>

Titan 2006-02-18 21:05 发表评论
]]>
վ֩ģ壺 Զ| | °Ͷ| | | ͬ| ƽ| ͼ| | | ²| | ˮ| | ̩| | | Դ| ٲ| | | ҵ| ָ| | ƴ| Ǹ| | | | ó| ף| | | | | ij| | ˮ| | | |