'''Newton's method for arbitrary differentiable functions.

Input: 
    fun ... function
    dfun ... derivative of the function
    x0 ... starting value
    maxk ... number of iterations; program terminates after maxk iterations

Output: 
    root xi and sequence of approximations X

Typical calls of program: 
    
Example 1: 
    from python08_2 import newton
    import numpy as np 
    newton(np.sin,np.cos,2.0,10)  # newton(fun, dfun, x0, maxk)

Example 2:
    from python08_2 import newton
    from python08_examplefun import f1, df1 
    newton(f1,df1,2.0,30)     # newton(fun, dfun, x0, maxk)

Example 3:
    from python08_2 import newton
    from python08_examplefun import f2, df2 
    newton(f2,df2,2.0)    # newton(fun, dfun, x0, maxk)

'''

def newton(fun, dfun, x0 = 0, maxk = 100):
    
    x = x0
    X = [x] 
    
    for k in range(maxk):
        x -= fun(x)/dfun(x)
        X += [x]
       
    xi = x

    print('root = ', xi)
    print('convercence history = ', X)