18

I'm looking for a numerically stable method for computing the angle between two 3D vectors. Which of the following methods ought to be preferred?

Method 1: $$ u \times v = \|u\| ~ \|v\| \sin(\theta) \textbf{n} \\ u \cdot v = \|u\| ~ \|v\| \cos(\theta) \\ \theta = \operatorname{arctan2}(\| u\times v \|, u\cdot v) $$

Method 2:

$$ \theta = 2 \operatorname{arctan2}\bigg(\bigg\|\frac{u}{\|u\|} - \frac{v}{\|v\|}\bigg\|, \bigg\|\frac{u}{\|u\|} + \frac{v}{\|v\|} \bigg\|\bigg) $$

where method 2 is based on the fact that the sum and difference vectors of two unit (or equal length) vectors are orthogonal.

Or is there an even better method which I haven't thought of? The vectors I am considering have angles typically smaller than 2 degrees.

user76284
  • 6,408
Murphy
  • 181

1 Answers1

18

Short answer: Method 2 is better for small angles. Use this slight rearrangement: $$ \theta = 2 \operatorname{arctan2}(\|\|v\|u - \|u\|v\|, \|\|v\|u + \|u\|v\|) $$

This formula comes from W. Kahan's advice in his paper "How Futile are Mindless Assessments of Roundoff in Floating-Point Computation?" (https://www.cs.berkeley.edu/~wkahan/Mindless.pdf), section 12 "Mangled Angles."

Before I found that paper, I also did my own analysis, comparing the double-precision results with result's using bc with 50 digits of precision. Method 2 is commonly within 1 ulp of correct, and almost always within 50 ulps, whereas Method 1 was much, much less accurate.

This might seem surprising, since Method 1 is mathematically insensitive to the magnitude of u and v, whereas they have to be normalized in Method 2. And indeed, the accuracy of the normalization is the limiting factor for Method 2 - virtually all the error comes from the fact that even after normalization, the vectors aren't exactly length 1.

However, for small angles you get catastrophic cancellation in the cross product for method 1. Specifically, all the products like $u_y v_z - u_z v_y$ end up close to 0, and I believe the cross-multiplication before the subtraction loses accuracy, compared to the direct subtraction in Method 2.

user76284
  • 6,408
D0SBoots
  • 525
  • 3
  • 13
  • 1
    What about the common method $\arccos(\frac{u \cdot v}{|| u || || v ||})$? – plasmacel Aug 17 '17 at 20:48
  • 6
    That's possibly the worst choice for small angles. $\frac{u \cdot v}{||u||||v||}$ approaches 1 for small angles, so you lose most of your precision. – D0SBoots Aug 23 '17 at 04:46
  • @D0SBoots I came to this question and your answer because I was indeed in crossroads trying to understand which algorithm should I use.

    You mention "catastrophic cancellation in the cross product" and also "ulp" (unit of least precision?) but I would like to realize these on my end. I've made this question: https://stackoverflow.com/questions/77610266/which-algorithm-is-more-accurate-for-calculation-of-the-angle-between-3d-vectors And would like to grasp why indeed Method2 is better than Method1, even though I'm more biased towards Method1. Thanks

    – probiner Dec 06 '23 at 04:46