Reputation: 63
I want to calculate the cosine of the angle of two 2D-vectors that lie on the same plane in Python. I use the classic formula cosθ = v1∙v2/(|v1||v2|). However, depending on how I implement it, the rounding errors can give values greater than 1 or less than -1 for parallel vectors. Three examples of the implementation follow:
import numpy as np
def cos2Dvec_1(v1,v2):
v1norm2 = v1[0]**2+v1[1]**2
v2norm2 = v2[0]**2+v2[1]**2
v1v2 = v1[0]*v2[0]+v1[1]*v2[1]
if v1v2 > 0:
return np.sqrt(v1v2**2/(v1norm2*v2norm2))
else:
return -np.sqrt(v1v2**2/(v1norm2*v2norm2))
def cos2Dvec_2(v1,v2):
r1 = np.linalg.norm(v1)
r2 = np.linalg.norm(v2)
return np.dot(v1,v2)/(r1*r2)
def cos2Dvec_3(v1,v2):
v1 = v1/np.linalg.norm(v1)
v2 = v2/np.linalg.norm(v2)
return np.dot(v1,v2)
v2 = np.array([2.0, 3.0])
v1 = -0.01 *v2
print(cos2Dvec_1(v2,v1), cos2Dvec_2(v1,v2), cos2Dvec_3(v1,v2))
When I execute this code on my machine (Python 3.7.6, Numpy 1.18.1), I get:
-1.0 -1.0000000000000002 -1.0
The difference between the 2nd and 3rd version of the function is especially weird to me...
If I use the second function to calculate the angle via the inverse cosine, I will get a nan
, which I want to avoid (and I don't want to check every time, if the result lies in [-1,1]). I was wondering though whether versions 1 and 3 (which give the correct result) are numerically stable in all cases.
Upvotes: 2
Views: 288
Reputation: 63
After timing numpy.clip(x,-1,1)
, I saw that a much faster alternative is just plain old y = max(-1, min(x,1))
. Timing results for the following code snippet:
t1 = time.time()
vals = [-1.001, -0.99, 0.99, 1.001]
for ii in range(1):
for x in vals:
y = np.clip(x, -1, 1)
# y = max(-1, min(x,1))
print(y)
t2 = time.time()
print(t2-t1)
Numpy clip was almost 23 times slower on my laptop.
Upvotes: 0
Reputation: 23174
You could use the clip
function to ensure values will be coerced (or "clamped" or "clipped") between -1 and 1.
return np.clip(YourOriginalResult, -1, 1)
Rounding errors are inevitable when manipulating floats. Unfortunately, I don't have enough expertise on your calculations to recommend any of your methods.
I'd suggest you to to check which ones have correct performance, after adding the clip
part to mitigate those "out of range" issues.
Upvotes: 1