Skip to content

Commit d2dd189

Browse files
committed
Less inaccurate implementation of Taylor series.
Clearer way to limit angle between -360 and 360 using modulo Avoid recalculating factorial(x) every iteration. Keep calculating until next term has no longer effect on the result. All existing doctests still succeed.
1 parent b61b469 commit d2dd189

1 file changed

Lines changed: 24 additions & 19 deletions

File tree

‎maths/sin.py‎

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,25 @@
11
"""
2-
Calculate sin function.
3-
4-
It's not a perfect function so I am rounding the result to 10 decimal places by default.
2+
Calculate the sine function, approximated by Taylor series expansion
53
64
Formula: sin(x) = x - x^3/3! + x^5/5! - x^7/7! + ...
7-
Where: x = angle in randians.
5+
Where: x = angle in randians.
86
97
Source:
108
https://www.homeschoolmath.net/teaching/sine_calculator.php
11-
9+
Wikipedia reference: https://en.wikipedia.org/wiki/Taylor_series
1210
"""
1311

14-
from math import factorial, radians
12+
from math import radians
1513

1614

17-
def sin(
18-
angle_in_degrees: float, accuracy: int = 18, rounded_values_count: int = 10
19-
) -> float:
15+
def sin(angle_in_degrees: float, rounded_values_count: int = 10) -> float:
2016
"""
21-
Implement sin function.
17+
Calculate the sine function, approximated by Taylor series expansion
18+
19+
For trigonometry calculations the expected precision is about 10 digits.
20+
Python has floating precision of about 15 digits.
21+
Using operation ** and / iteratively, precision is lost quickly
22+
This method rounds to 10 digits by default, to be safe.
2223
2324
>>> sin(0.0)
2425
0.0
@@ -41,21 +42,25 @@ def sin(
4142
>>> sin(89.7)
4243
0.9999862922
4344
"""
45+
4446
# Simplify the angle to be between 360 and -360 degrees.
45-
angle_in_degrees = angle_in_degrees - ((angle_in_degrees // 360.0) * 360.0)
47+
angle_in_degrees %= 360.0
4648

47-
# Converting from degrees to radians
4849
angle_in_radians = radians(angle_in_degrees)
4950

5051
result = angle_in_radians
51-
a = 3
52-
b = -1
53-
54-
for _ in range(accuracy):
55-
result += (b * (angle_in_radians**a)) / factorial(a)
52+
power_x = 3
53+
fac = -6 # - factorial(power_x)
54+
result_old = 2 # any impossible sine result will do
5655

57-
b = -b # One positive term and the next will be negative and so on...
58-
a += 2 # Increased by 2 for every term.
56+
# Keep adding the next Tayler term until the result stops changing.
57+
while True:
58+
result += angle_in_radians**power_x / fac
59+
power_x += 2 # Increased by 2 for every term.
60+
fac *= -power_x * (power_x - 1)
61+
if result == result_old:
62+
break
63+
result_old = result
5964

6065
return round(result, rounded_values_count)
6166

0 commit comments

Comments
 (0)