检查两个向量是否并行的最有效方法

Most efficient way to check if two vectors are parallel

本文关键字:并行 有效 方法 是否 向量 两个 检查      更新时间:2023-10-16

给定两个向量u=(ux,uy,uz)v=(vx,vy,vz),,假设向量没有归一化,检查它们是平行的还是接近平行的(给定一些近似阈值(的最便宜的计算方法是什么?

关于平行:例如,我们假设一个阈值直到小数点的第一部分,例如,如果它们的交叉乘积0.01我们可以安全地假设它们是平行的。我们同样可以放宽我们可能想要使用的其他方法的条件。

如果最好坚持使用编程语言来回答,让我们假设我们想用 C++ 来回答这个问题。

  • 计算它们之间的角度成本很高,因为它需要使用反三角函数。
  • 计算他们的交叉乘积可能是一种方法,但不确定它是否是最有效的方法。
  • 规范化它们并验证它们的标量产品是否为标量产品。

简短回答: 从理论上讲,这根本不重要。实际操作:测量它

长答案:

同意反三角函数是不可能的,让我们比较计算最后两个选项的最有效方法。

计算他们的交叉乘积

由于允许向量几乎平行,因此需要计算

crossx := uy * vz + uz * vy;
crossy := ...;
crossz := ...;
crossNorm = crossx * crossx + crossy * crossy + crossz * crossz;

其中涉及 9 次乘法和 5 次加法。如果向量(几乎(平行,则crossNorm应(接近(为零。

然而,正如 Baum mit Augen 正确指出的那样,检查crossxcrossycrossz几乎为零就足够了,将其减少到 6 次乘法和 3 次加法,代价是最多再进行两次比较。哪个更有效,取决于你的语言的细节和"几乎"相等的定义——例如,如果接近相等意味着fabs(...) < 1E-6可能只做一次就值得。

计算标量积

标量乘积是

scalar = ux * vx + uy * vy + uz * vz;

如果向量(几乎(平行,则

scalar * scalar

应该(几乎(相等

(ux * ux + uy * uy + uz * uz) * (vx * vx + vy * vy + vz * vz).

这归结为 10 次乘法和 6 次加法。

规范化它们并验证它们的标量产品是否为标量产品。

这只是上面的计算,但有两个额外的double划分。这不会增加任何价值,实际上它可能只会引入舍入问题。

结论

两个选项的双重操作数量几乎相同。如果你真的想知道,你可以比较组装 https://godbolt.org/z/nJ9CXl 但对于所有实际目的来说,差异将是最小的。事实上,如果你只计算"昂贵"的指令(mulsdaddsdsubsd(和比较(ucomisd(,两个选项都有五个。但是,同样,如果您必须确切地知道,请测量它!

我认为这是错误的

标量=L1*L2*cos(r(=UX * VX + UY * vy + uz * vz 标量^2=(L1*L2*cos(r((^2=(UX * VX + UY * vy + uz * vz(^2

(L1*L2(^2= (UX * UX + UY * UY + UZ * uz( * (VX * VX + vy * vy + vz * vz( 所以 cos(x(^2 =scalar^2/(ux * ux + uy * uy + uz * uz( * (vx * vx + vy * vy + vz * vz(= (UX * VX + UY * vy + uz * vz(^2/(UX * UX + uy * uy + uz * uz( * (vx * vx + vy * vy + vz * vz(

当 cos 为 1 或 -1 时,x 接近 0 或 180,因此 cos(x(^2 -> 1

当这个

福尔米拉接近 1

(UX * VX + UY * vy + uz * vz(^2/(UX * UX + uy * uy + uz * uz( * (vx * vx + vy * vy + vz * vz( 这意味着向量是平行的