Search code examples
c++vectorgeometrycomputation-theory

Most efficient way to check if two vectors are parallel


Given two vectors u=(ux,uy,uz) and v=(vx,vy,vz), what is the computationally cheapest way of checking whether they are parallel or nearly parallel (given some threshold to approximate), assuming the vectors are not normalized?

Regarding nearly parallel: for instance we assume a threshold up to first decimal part, e.g., if their cross product is 0.01 we can safely assume them to be parallel. We can similarly relax the condition for other methods we may want to use.

If it is preferred to adhere to a programming language to answer, let us assume we want to do this in c++.

  • Computing the angle between them is costly because it requires using inverse trigonometric functions.
  • Computing their cross product may be a way but not sure if it is the most efficient one.
  • Normalizing them and verifying if their scalar product is one.

Solution

  • Short answer: Theoretically, it doesn't matter at all. Practically: measure it

    Long answer:

    Agreeing that the inverse trigonometric functions are out of the question, let's compare the most efficient ways of calculating the last two options.

    Computing their cross product

    Since you allow for the vectors to be nearly parallel, you need to calculate

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

    which involves 9 multiplications and 5 additions. If the vectors are (nearly) parallel then crossNorm should be (nearly) zero.

    However, as correctly noted by Baum mit Augen, it is sufficient to check that crossx, crossy and crossz are almost zero, reducing this to 6 multiplications and 3 additions, at the expense of up to two more comparisons. Which is more efficient, depends on the details of your language and definition of "nearly" equal – e.g. if nearly equals means that fabs(...) < 1E-6 it may be worth only having to do it once.

    Calculating the scalar product

    The scalar product is

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

    If the vectors are (nearly) parallel then

    scalar * scalar
    

    should (nearly) equal

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

    This comes down to 10 multiplications and 6 additions.

    Normalizing them and verifying if their scalar product is one.

    This is just the above calculation but with two extra double divisions. This does not add any value, in fact it may just introduce rounding problems.

    Conclusion

    The number of double operations is nearly the same for both options. If you really want to know, you can compare the assembly https://godbolt.org/z/nJ9CXl but the difference is going to be minimal for all practical purposes. In fact, if you only count the "expensive" instructions (mulsd, addsd, subsd) and the comparisons (ucomisd) both options have five of them. However, again, if you must know exactly, measure it!