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

Most efficient way to check if two vectors are parallel

给定两个向量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 应该(几乎)为零。

然而,正如 正确指出的那样,检查 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 =标量^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) 这意味着向量是平行的