问题是关于这个相当基本的操作的最强大和最快的实现:
给定向量(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)的方向并在该方向上形成desiredLength的向量:
if(X == 0 && Y == 0) { /* Aye, Caramba! */ }
double angle = atan2(Y, X);
X = desiredLength * cos(angle);
Y = desiredLength * sin(angle);
哪种方法更适合开发强大的应用程序,更好的数值稳定性,更快的执行等?
答案 0 :(得分:2)
没有一个正确的答案,因为它将取决于实施。
但是:对任何合理的现代实施,四个基本
操作和sqrt
将精确到最后一位二进制数字。从一个
从实施质量来看,人们希望也一样
对math.h
中的所有函数都是如此,但它更少
某些。在具有IEEE算法的机器上(Windows和主流
Unix平台),将实现四个操作和 sqrt
硬件,其中三角运算通常需要一个
软件实现,通常需要数十个基本操作。
虽然一些浮点处理器确实直接支持它们,但是
至少在有限的范围内,即使这样,它们通常也会慢一些
比四个基本操作。
所有这些都支持你的第一次实施,至少是 关于速度(可能与数值稳定性有关) 孔)。
答案 1 :(得分:1)
我希望方法一更好至少在性能方面,因为sqrt + 2乘法应该比3个trig操作便宜。 我猜它在其他方面也更好(或者更糟),因为它涉及一个近似值(sqrt)而不是2(每个轴)。 sqrt近似也由x和y“共享”。
答案 2 :(得分:1)
最好使用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中处理它。