def bisection(a, b, fn, e):
    """
    S vyuzitim metody Bisekcie vypocita koren funkcie fn na intervale <a,b>.
    """

    assert a < b, 'Cislo b musi byt vacsie ako cislo a'
    assert e > 0, 'Presnost e musi byt vacsia ako nula'

    f = lambda x: eval_expr(fn, x=x)

    while True:
        # stred intervalu <a,b>
        x = 0.5 * (a + b)

        logger.info('a = {0}, b = {1}, x = {2}'.format(a, b, x))

        # skonci ak je stred intervalu
        # korenom funkcie inak uprav interval
        if f(x) == 0:
            return x
        elif f(a) * f(x) < 0:
            b = x
        else:
            a = x

        # skonci pri dosiahnuti presnosti
        if b - a <= e:
            return x
def newton(a, b, fn, e):
    """
    S vyuzitim Newtonovej metody vypocita koren funkcie fn na intervale <a,b>.
    """

    assert a < b, 'Cislo b musi byt vacsie ako cislo a'
    assert e > 0, 'Presnost e musi byt vacsia ako nula'

    # urci prvu a druhu derivaciu funkcie
    fn_d1 = diff(fn)
    fn_d2 = diff(fn_d1)

    logger.info('fn_d1 = {0}, fn_d2 = {1}'.format(fn_d1, fn_d2))

    f = lambda x: eval_expr(fn, x=x)
    fd = lambda x: eval_expr(fn_d1, x=x)
    fd2 = lambda x: eval_expr(fn_d2, x=x)

    # aspon jeden z bodov musi splnit podmienku
    # inak je potrebne upravit interval
    if f(a) * fd2(a) > 0:
        x = a
    elif f(b) * fd2(b) > 0:
        x = b
    else:
        raise ValueError('aspon jeden z bodov a alebo b musi '
                         'splnat podmienku f(x) * fd2(x) > 0')

    while True:
        # vypocet priesecnika s osou x
        x1 = x - f(x) / fd(x)

        logger.info(
            'x = {0}, x1 = {1}, Abs(x1 - x) = {2}'.format(x, x1, Abs(x1 - x)))

        # skonci pri dosiahnuti presnosti
        if Abs(x1 - x) <= e:
            return x1

        x = x1
def trapezoid(a, b, m, fn, e):
    """
    Na intervale <a,b>, ktory sa rozdeli na m lichobeznikov, vypocita
    aproximaciu urciteho integralu funkcie fn.
    """

    assert a < b, 'Cislo b musi byt vacsie ako cislo a'
    assert e > 0, 'Presnost e musi byt vacsia ako nula'

    f = lambda x: eval_expr(fn, x=x)
    I = []
    J1 = 0
    J2 = 0
    k = 0

    # rozdelenie intervalu na m rovnako dlhych dielov
    h = (b - a) / m

    for i in range(m):
        J1 += f(a + (h * i))
        J2 += f(a + h * (i + 1))

    I.append((h / 2) * (J1 + J2))

    while True:
        J1 = 0
        J2 = 0
        m *= 2

        # skratenie intervalu na polovicu
        h /= 2

        for i in range(m):
            J1 += f(a + (h * i))
            J2 += f(a + h * (i + 1))

        I.append((h / 2) * (J1 + J2))

        logger.info('m = {0}, h = {1}, Abs(I[k] - I[k + 1]) = {2}'.format(
            m, h, I[k] - I[k + 1]))

        # skonci pri dosiahnuti presnosti
        if Abs(I[k] - I[k + 1]) <= e:
            return I[k + 1]

        k += 1