1

问题是关于这个相当基本的操作的最健壮和最快的实现:

给定一个向量 (X,Y),计算给定长度 desiredLength 的共线向量。至少有两种方法:

一。求 (X,Y) 的长度并相应地重新缩放:

double currentLength = sqrt(X*X + Y*Y);
if(currentLength == 0) { /* Aye, Caramba! */ }
double factor = desiredLength / currentLength;
X *= factor;
Y *= factor;

二。求 (X,Y) 的方向并在该方向形成一个所需长度的向量:

if(X == 0 && Y == 0) { /* Aye, Caramba! */ }
double angle = atan2(Y, X);
X = desiredLength * cos(angle);
Y = desiredLength * sin(angle);

哪种方法更适合开发健壮的应用程序、更好的数值稳定性、更快的执行等等?

4

3 回答 3

2

没有一个正确的答案,因为它取决于实施。但是:在任何合理的现代实现中,四个基本操作sqrt都将精确到最后一个二进制数字。从实现质量的角度来看,人们希望对 中的所有功能都适用同样的事情math.h,但不太确定。在具有 IEEE 算法(Windows 和主流 Unix 平台)的机器上,这四个运算将在硬件中实现,而三角运算通常需要软件实现,通常需要数十个以上的基本运算 sqrt尽管一些浮点处理器确实直接支持它们,至少在有限的范围内,即使那样,它们通常比四个基本操作慢一个数量级。

所有这些都支持您的第一次实现,至少在速度方面(并且可能在数值稳定性方面也是如此)。

于 2013-09-23T18:22:15.477 回答
1

Thu 应该更好地使用hypot(x,y),而不是sqrt(x*x+y*y)因为合理的 hypot 实现可以使您免于下溢/溢出条件。

示例:hypot(1.0e300,1.0e300)hypot(1.0e-300,1.0e-300)

然后评估 x/hypot(x,y) 是安全的,即使在 x=1.0e-320, y=0 等逐渐下溢(非规范化数字)的情况下,同时评估 desiredLength/hypot(x,y) 可能会溢出。

所以我会写

double h  = hypot(x,y);
double xd = desiredLength*(x/h);
double yd = desiredLength*(y/h);

如果 x,y 都为零,您将得到一些除以零异常和 nan 结果,所以不要费心在 if 中处理它。

于 2013-09-24T01:47:49.413 回答
1

我希望方法一会更好至少在性能方面,因为做 sqrt + 2 乘法应该比 3 trig 操作便宜。我猜想它在其他方面也更好(或不是更糟),因为它涉及一个近似值(sqrt)而不是 2 个(每个轴)。sqrt 近似值也被 x 和 y “共享”。

于 2013-09-23T18:23:24.147 回答