test_estimation.py 1.77 KB
from decimal import Decimal
from sympy import series, atan, nsimplify, diff
from sympy.calculus.util import Interval, maximum
from math import floor, factorial
from src.taylor import arctan

import pytest
from sympy.abc import x

def term(N, xval, a):
    ivl = Interval(xval - 0.001, a + 0.001) + Interval(a - 0.001, xval + 0.001)
    d = diff(atan(x), x, N + 1)
    M = maximum(d, x, ivl)
    return nsimplify(abs(((M * ((x - a)**(N + 1))/factorial(N + 1)).subs(x, xval))))

def ref_taylor(f, a, N, xval):
    return nsimplify(series(f, x=x, x0=a, n=N).removeO().subs(x, xval).doit())

EPSILON = 0.0001

def approx_atan(N, xval):
    if floor(xval) == 0:
        return ref_taylor(atan(x), 0, N, xval), term(N, xval, 0)
    else:
        _, center_error = approx_atan(N, floor(xval) - EPSILON)
        return ref_taylor(atan(x), floor(xval), N, xval), center_error + term(N, xval, floor(xval) - EPSILON)

@pytest.mark.parametrize('xval', [x/10 for x in range(20)])
def test_arctan(xval):
    print('testing', xval)
    ref_val1, ref_error = approx_atan(10, xval)
    ref_val1 = float(ref_val1)
    ref_error = float(ref_error)
    ref_val2 = atan(xval)
    our_val, our_error = arctan(Decimal(xval))
    our_val = float(our_val)
    our_error = float(our_error)

    errors_diff = our_error - ref_error
    error_with_ref1 = abs(ref_val1 - our_val)
    error_with_ref2 = abs(ref_val2 - our_val)
    epsilon = 0.15
    if xval < 0.5:
        epsilon = 0.001
    elif xval < 1.0:
        epsilon = 0.05
    assert 0 <= errors_diff < epsilon
    assert error_with_ref1 <= our_error
    assert error_with_ref2 <= our_error
    assert abs(error_with_ref2 - our_error) < epsilon

if __name__ == "__main__":
    test_arctan(0.0)
    test_arctan(0.5)
    test_arctan(0.9)
    test_arctan(1.0)
    test_arctan(1.5)