taylor.py 2.94 KB
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) + ')')