1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
from math import floor
import support.parsing
from support.canonicalize import *
from src.newton import newton
from src.differentiation import evaluate_diff
from math import factorial, ceil
@cache
def nth_derivative(func, n):
"""self explanatory for now..."""
return None
@cache
def taylor(func, x, N):
"""
Returns the taylor expansion of func as a function of x, centered at 'b'.
Since the 0th term is just the function itself (which we don't have the answer for yet),
it should be replaced with a variable 'q' instead of the actual function.
The expansion should go to N terms (see variable defined above).
"""
return None
def taylor_at(func, b, f_at_b, N):
"""
Returns taylor(-), evaluated by plugging in f_at_b for 'q' and b for 'b'.
"""
return None
def max_error(func, a, x, n):
"""
Calculates the maximum error of the estimate below using Taylor's Theorem
in the following way.
Taylor's Theorem says that we can upper bound the error of a taylor series with N terms
with the following expression for some a <= c <= x (or x <= c <= a, symmetrically):
error(x) = f^(N + 1)(c) * (x - a)^(N + 1)/(n+1)!
So, if we can find an upper bound for f^(N + 1)(c), then we can upper bound the error.
We consider three cases:
1) f^(N + 1) is increasing on the interval [a, x]. Then, f^(N + 1)(x) is the maximum.
2) f^(N + 1) is decreasing on the interval [a, x]. Then, f^(N + 1)(a) is the maximum.
3) There is a turning point on the interval [a, x]. Then, we need to attempt to find
the maximum in that interval. To do this, we find a zero of f^(N + 2), which indicates
a maximum in f^(N + 1). To do that, we use our newton(-) function from the previous part
on f^(N + 2) with an initial guess of x.
Then, we take the max of the absolute value of each of the 3 cases. This should give us some M,
where M >= f^(N + 1)(c).
Finally, plug M into the equation above for f^(N + 1)(c) and return that value.
"""
return None
@cache
def estimate(func, x, a, func_at_a, N):
"""
Uses the taylor expansion centered around a to compute an estimate for func(x).
"""
return None
PI = 3.14159265358979323846264338327950288419716939937510582097494
def arctan(x):
N = 10
if x == 0:
return 0, 0
elif x == 1:
return pi/4, Decimal(10**-16)
a = 0
total_error = Decimal(0)
prev_value = 0
while a + 1 <= x:
prev_value = estimate('arctan', a + 1, a, prev_value, N)
total_error += max_error('arctan', a, a + 1, N)
a += 1
return estimate('arctan', x, floor(x), prev_value, N), total_error + max_error('arctan', floor(x), x, N)
if __name__ == "__main__":
for i in range(0, 4):
for j in range(10):
x = i + j/10
v, e = arctan(Decimal(x))
print('arctan(' + str(x) + ') =', v, '(error <= ' + str(e) + ')')