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

时间:2018-09-04 11:13:07

标签: c++ vector geometry computation-theory

给定两个向量u=(ux,uy,uz)v=(vx,vy,vz),,假定向量是并行的或(给定一些近似值),那么检查它们的计算上最便宜的方法是什么没有规范化?

关于几乎平行:例如,我们假设一个阈值一直到小数点后第一位,例如,如果它们的叉积为0.01,则可以安全地假定它们是平行的。我们可以类似地放宽我们可能要使用的其他方法的条件。

如果首选使用编程语言来回答问题,让我们假设我们想使用c ++来实现。

  • 计算它们之间的角度是昂贵的,因为它需要使用反三角函数。
  • 计算他们的叉积可能是一种方法,但不确定是否是最有效的方法。
  • 将它们归一化并验证其标量乘积是否为1。

2 个答案:

答案 0 :(得分:5)

简短答案: 从理论上讲,这根本没有关系。实际上:对其进行测量

长答案:

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

计算他们的叉积

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

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),则两个选项都有五个。但是,再次提醒您,如果您必须准确地了解

答案 1 :(得分:0)

我认为这是错误的

标量= 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)

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

何时

formila接近1

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