Recursive Trigonometric Functions¶
In this notebook we shall see how we can compute the sine and cosine functions using recursion.
The root function computes the square root of a floating point number using binary search.
In [1]:
PI = 3.14159265359
full_angle = PI * 2
half_angle = PI / 2
# function to find x-th root of n
def root(n:float, x:int) -> float:
# Max and min are used to take into account numbers less than 1
lo = min(1, n)
hi = max(1, n)
mid = 0.0
# Update the bounds to be off the target by a factor of 10
while(100 * lo * lo < n):
lo *= 10
while(0.01 * hi * hi > n):
hi *= 0.1
for i in range(100):
mid = (lo + hi)/2
val = mid ** x
if(val == n): return mid
if(val > n): hi = mid
else: lo = mid
return mid
The range_check decorator normalises the input to fit between $-6.28$ and $6.28$
In [2]:
to_radians = lambda deg: ((deg % 360)/180.0) * PI
abs = lambda x: (x if x >= 0 else -x)
def range_check(func):
def inner(*args):
angle = (args[0] % full_angle) * (-1 if args[0] < 0 else 1)
return func(angle)
return inner
The sine< and cosine function approximates the sine and cosine of a given angle
Modify the value of DELTA to adjust the accuracy.
Formulas used:¶
- $\sin(2x) = 2\sin(x)\cos(x)$
- $\cos(2x) = 2\cos^2(x) - 1$
Note:¶
- Since we're finding then square root for computing sine, whether we take the positive or negative value depends on the quadrant of the input.
- We don't need to check the quadrant for every recursion call.
In [3]:
DELTA = 0.001
@range_check
def cosine(x:float) -> float:
if x == 0.0:
return 1.0
if abs(x) < DELTA:
return x
else:
v = cosine(x / 2.0)
return 2.0 * v * v - 1
@range_check
def rec_sine(x:float) -> float:
if abs(x) < DELTA:
return x
else:
v = rec_sine(x / 2.0)
return 2.0 * v * root(1 - v * v, 2)
sine = lambda x: rec_sine(x) * (-1 if x <= full_angle and x >= PI else 1)
Driver code¶
In [4]:
if __name__ == "__main__":
args = [0, 30, 45, 60, 90, 120, 270]
for i in args:
print(f"sin({i}) = {round(sine(to_radians(i)), 3)}")
print(f"cos({i}) = {round(cosine(to_radians(i)), 3)}\n")
sin(0) = 0.0 cos(0) = 1.0 sin(30) = 0.5 cos(30) = 0.866 sin(45) = 0.707 cos(45) = 0.707 sin(60) = 0.866 cos(60) = 0.5 sin(90) = 1.0 cos(90) = -0.0 sin(120) = 0.866 cos(120) = -0.5 sin(270) = -1.0 cos(270) = 0.0