2维快速距离算法(Fast_Distance_2D)的解释

来源:互联网 发布:小学生编程软件下载 编辑:程序博客网 时间:2024/04/28 20:21

在平面上如果有2个点P0(x0,y0),P1(x1,y1),根据勾股定理这2点之间的距离是√((x0-x1)^2+(y0-y1)^2)。

但是sqrt()开平方根函数是费时的操作。

所以《Windows游戏编程大师技巧》中介绍了一个2维快速距离算法(Fast_Distance_2D)。

#define MIN(a, b) ((a < b) ? a : b)#define MAX(a, b) ((a > b) ? a : b)#define SWAP(a, b, t) {t = a; a = b; b = t;}int Fast_Distance_2D(int x, int y){// this function computes the distance from 0,0 to x,y with 3.5% error// fist compute the absolute value of x,yx = abs(x);y = abs(y);// compute the minimum of x,yint mn = MIN(x, y);// return the distancereturn (x + y - (mn >> 1) - (mn >> 2) + (mn >> 4));} // end Fast_Distance_2D

这个函数是求某一点(x, y)到原点(0,0)的近似距离。有大约3.5%的误差。如果要求P0(x0,y0),P1(x1,y1)之间的距离,则调用时可以写成如下形式:

dist = Fast_Distance_2D(x0 - x1, y0 - y1);

对于这个算法为什么可以这样写,作者提到了到了泰勒•麦克劳林级数展开式,即

f(x)可以表示为f(0)+f'(0)*x1/1!+f''(0)*x2/2!+...f(n)(0)*xn/n!

其中最后一项的f(n)(0)应该是指f(x)在0处的n次导数。

但是对于这是如何变成x + y - (1/2)*mn - (1/4)*mn + (1/16)*mn的原因,作者没有详细解释。

要研究这个问题,首先要把公式搞清楚。查看《高等数学》可以找到确切的描述:


泰勒(Taylor)中值定理  如果函数f(x)在含有x0的某个开区间(a, b)内具有直到(n+1)阶的导数,则当x在(a, b)内时,f(x)可以表示为(x-x0)的一个n次多项式与一个余项Rn(x)之和:

该公式称为f(x)按(x-x0)的幂展开的n阶泰勒公式。余项Rn(x)有多种形式。

在泰勒公式中,如果取x0=0,则可得到所谓的麦克劳林(Maclaurin)公式

显然《Windows游戏编程大师技巧》第二版所写的公式实在是太粗糙了。

我们要求开平方根,那么把f(x)设为√x是不是就可以了呢?让我们试试看求它的导数。

f(x)=√x

f'(x)=(√x)'

根据导数公式(x^u)'=u·x^(u-1)

f'(x)=(x^(1/2))'=1/(2√x)

然后把0带入,发现0在分母位置。所以把f(x)设为√x无法运用麦克劳林公式。

那该怎么办呢?让我看看√x和它的导数1/(2√x)的曲线:


可以发现,如果把曲线向左偏移,则可以使0成为有效值。比如把f(x)设为√(x+1)


f(x)=√(x+1)则f'(x)=1/(2√(x+1))

我们可以继续计算得到2阶,3阶导数。所以有:


所以√(x+1)的麦克劳林公式为


为了便于理解,让我们用这个公式算一下√30。

为了运用公式,应该把它写成√(x+1)的形式:√30=√(25+5)=5*√(1+1/5)=5*(1+1/2*1/5-1/8*(1/5)^2+1/16*(1/5)^3+...)=5*(1+1/10-1/200+1/2000+...)约等于5.4775

用计算器算得5.477225575051661。看来是可以这样计算的。但其实还有另一个问题:既然要写成√(x+1)的形式,为什么不写成√(29+1)?把29带入公式,则会发现结果完全不对。

问题出在哪里?难道对于x还有其它条件的限制吗?经过再次研究才发现上面混淆了泰勒公式与泰勒级数,麦克劳林公式与麦克劳林级数的区别。《Windows游戏编程大师技巧》说的是泰勒•麦克劳林级数展开式,没有说泰勒•麦克劳林公式。

所以下面要开始讨论级数。

如果给定一个定义在区间I上的函数列u1(x),u2(x),u3(x),...,un(x),...则由这函数列构成的表达式u1(x)+u2(x)+u3(x)+...+un(x)+...

称为定义在区间I上的(函数项)无穷级数,简称(函数项)级数

函数项级数中简单而常见的一类级数就是各项都是幂函数的函数项级数即所谓幂级数

泰勒公式的等式右边取除余项的部分就是泰勒级数。在泰勒级数中取x0=0则为麦克劳林级数。

泰勒•麦克劳林公式只是说有这样一个等式成立。并不保证能用这个多项式的前几项之和来逼近f(x)。

所以要继续研究“函数展开成幂级数”的问题。“函数展开成幂级数”就是指,是否能找到这样一个幂级数,它在某个区间内收敛,且其和恰好就是给定的函数f(x),如果能找到这样的幂级数,我们就说,函数f(x)在该区间内能展开成幂级数,或简单地说函数f(x)能展开成幂级数,而该级数在收敛区间内就表达了函数f(x)。

有这样一个定理 设函数f(x)在点x0的某个领域U(x0)内具有各阶导数,则f(x)在该领域内能展开成泰勒级数的充分必要条件是f(x)的泰勒公式中的余项Rn(x)当n->∞时的极限为零。

所以函数展开成幂级数是有条件的。对于√(x+1)=1+(1/2)x-(1/8)x^2+(1/16)x^3+... 条件是-1<=x<=1。具体计算过程请看《高等数学》下册第十一章第四节例6。

现在我们可以回到Fast_Distance_2D。

Fast_Distance_2D其实要算的是√(x^2+y^2)。为了使用√(x+1)=1+(1/2)x-(1/8)x^2+(1/16)x^3+...就要将√(x^2+y^2)转换√(x+1)的形式。

为了对x做出区别,把√(x+1)=1+(1/2)x-(1/8)x^2+(1/16)x^3+...中的x换成z,得√(z+1)=1+(1/2)z-(1/8)z^2+(1/16)z^3+... (-1<=z<=1)

并且转换√(x^2+y^2)的形式:

然后令z=y^2/x^2,就可以带入级数展开式了。因为要满足-1<=z<=1,所以上式是假设|y|<=|x|。如果|x|<=|y|,上式就要改写成|y|√(1+x^2/y^2)。它们的形式是一样的。这就是Fast_Distance_2D中为什么要先取x,y的绝对值再取最小值的原因。

现在我们终于可以开始研究最后一行return (x + y - (mn >> 1) - (mn >> 2) + (mn >> 4));

把z=y^2/x^2带入级数展开式

但是(x + y - (mn >> 1) - (mn >> 2) + (mn >> 4))实际上是

这里是假设|y|<=|x|

这与上面的计算结果有点不一样。

所以《Windows游戏编程大师技巧》说这个算法有3.5%的误差。





1 0
原创粉丝点击