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)