I don't know if the full implementations might be a little on the large size - not to mention slow. OTOH there's a lot to be said for full cPython compatibility. In embedded applications it's common to use approximate, fast functions for trig where errors are determined by sensors rather than maths. Out of curiosity I tested the methods outlined in the article I cited.
Code: Select all
import math # for test only
PI = 3.141592653
def approxatan2(q, i): # q is imaginary part
K = 0.28125
if (q < 0 and i < 0 and -q <= -i):
q, i = i + q, i - q
return -3*PI/4 - i*q/(q*q + K*i*i)
if (q >=0 and i >= 0 and q <= i) or (q <= 0 and i >= 0 and -q <= i): # 1st or 8th octant
return i*q/(i*i + K*q*q)
if (q >=0 and i >= 0 and q >= i) or (q >= 0 and i <= 0 and q >= -i): # 2nd or 3rd
return PI/2 - i*q/(q*q + K*i*i)
if (q >= 0 and i <= 0 and q <= -i) or (q <= 0 and i <= 0 and -q <= -i): # 4th or 5th
return PI + i*q/(i*i + K*q*q)
return -PI/2 - i*q/(q*q + K*i*i)
# Method described in Rafc's comment adapted for two argument arctan (full 2*PI range)
def atan_approx(x):
b = 0.596227
return (PI/2)*(b*x + x*x)/(1 + 2*b*x + x*x)
def atan2_approx(q, i):
if i > 0: # In quadrants 1,2,7,8
x = q/i
if x >= 0:
return atan_approx(x)
return -atan_approx(-x)
else:
i, q = -i, -q # rotate by PI to put in q 1,2,7,8
x = q/i
if x >= 0:
return atan_approx(x) - PI
return -atan_approx(-x) + PI
def test():
for func in (approxatan2, atan2_approx):
maxerror = 0.0
for i in (1.0, -1.0):
q = -40
while q < 40:
theirs, mine = math.atan2(q,i), func(q,i)
error = theirs -mine
maxerror = max(maxerror, abs(error))
if abs(error) > 0.1:
print("i = {:7.4f} q = {:7.4f}".format(i,q))
print("math {:7.4f} mine {:7.4f} error {:7.4f}".format(theirs, mine, error))
q += 0.01
print("Max error (radians): {:7.4f} degs: {:7.4f}".format(maxerror, maxerror*180/PI))
For obvious reasons the test only works in cPython.
Results as expected:
>>> atan.test()
Max error (radians): 0.0049 degs: 0.2813
Max error (radians): 0.0028 degs: 0.1620
As for the two algorithms, you pays yer money and you makes yer choice
Regards, Pete