views:

970

answers:

6

Finding the angle between two vectors is not hard using the cosine rule. However, because I am programming for a platform with very limited resources, I would like to avoid calculations such as sqrt and arccos. Even simple divide's should be limited as much as possible.

Fortunately, I do not need the angle perse, but only need some value that is proportional to said angle.

So I am looking for some computationally cheap algorithm to calculate a quantity that is related to the angle between two vectors. So far, I haven't found something that fits the bill, nor have I been able to come up with something myself.

Any help is appreciated.

Jeroen

+2  A: 

The solution would be trivial if the vectors were defined/stored using polar coordinates instead of cartesian coordinates (or, 'as well as' using cartesian coordinates).

ChrisW
Sadly, this is not the case. The only way would be to convert the coordinates to polar in my code, but that runs into the same problem that I'm trying to solve in the first place.
Jeroen
A: 

The dot product might work in your case. It's not proportional to the angle, but "related".

Malte Clasen
OP knows that, dot product requires an arccos to yield an angle
Jason S
Or square roots to normalize lengths. Both of which the OP is trying to avoid.
David Thornley
+8  A: 

Back in the day of a few K of RAM and machines with limited mathematical capabilities I used lookup tables and linear interpolation. The basic idea is simple: create an array with as much resolution as you need (more elements reduce the error created by interpolation). Then interpolate between lookup values.

Here is an example in processing: http://processing.org/hacks/hacks%3Asincoslookup

You can do this with your other trig functions as well. On the 6502 processor this allowed for full 3D wire frame graphics to be computed with an order of magnitude speed increase.

Godeke
+1: interpolation into tables -- fast and small. Not so accurate, but often accurate enough. 256 distinct cosine values is often enough.
S.Lott
Thanks for the suggestion, but that would still only get rid of the arccos. determining the remaining elements of the cosine rule in this case (the lengths of all sides of the triangle) would still require several sqrt's.
Jeroen
Less than that can be enough. If you're willing to do a little extra calculation, you only need values between zero and half of pi/90 degrees, and of course you need to decide the granularity and accuracy you need. It's hard to say anything definite about details without considering the individual case.
David Thornley
SQRT is trivial to replace with an approximation loop that converges rapidly with plenty of accuracy. And it involves no divides, just multiplies.
S.Lott
CORDIC is a great solution if you don't have a multiplier, but if you do have one on your system I suspect that the interpolation will be faster (realizing that you can build such a table for SQRT as well over your domain). CORDIC is iterative while lookup/interpolate is fixed cost. My domain of experience is 3D on low end hardware though, so maybe your hardware will find CORDIC amiable.
Godeke
+1  A: 

dot product of two vectors (x1, y1) and (x2, y2) is

x1 * x2 + y1 * y2

and is equivilent to the product of the lengths of the two vectors times the cosine of the angle between them.

So if you normalize the two vectors first (divide the coordinates by the length)

Where length of V1 L1 = sqrt(x1^2 + y1^2),  
  and length of V2 L2 = sqrt(x2^2 + y2^2),

Then normalized vectors are

(x1/L1, y1/L1),  and (x2/L2, y2/L2),

And dot product of normalized vectors (which is the same as the cosine of angle between the vectors) would be

 (x1*x2 + y1*y2)
 -----------------
     (L1*L2)

of course this may be just as computationally difficult as calculating the cosine

Charles Bretana
OP knows that, dot product requires an arccos to yield an angle
Jason S
@Jason, yes, but dot product by itself is a "quantity that is related to the angle" you don;t necessarily have to convert it to radians or degrees to use it...
Charles Bretana
+1  A: 

if you need to compute the square root, then consider using the invsqrt hack.

acos((x1*x2 + y1*y2) * invsqrt((x1*x1+y1*y1)*(x2*x2+y2*y2)));
neoneye
Unless there are overflow issues, I'd combine the invsqrt's into one call invsqrt((x1*x1+y1*y1)*(x2*x2+y2*y2)); better to run a complex algorithm once rather than twice.
Jason S
excellent observation :-)
neoneye
+8  A: 
Jason S
+1. CORDIC is what you want. It may be faster to rotate the two vectors simultaneously towards the X axis, keeping track of the angle difference.
Eric Bainville
... and CORDIC will give you the norm of each vector for free.
Eric Bainville
@Eric: good point about rotating vectors simultaneously.
Jason S
Nice. CORDIC seems like it will do what I need. I haven't implemented this yet, but will mark your answer as "accepted" anyway.Thanks!
Jeroen