# Black magic to find the name of a function.
def name(fn):
    return fn.__name__

def args_to_string(args):
    string = ''
    for arg in args:
        string += str(arg) + ' '
    return string

# Meant to be used as a decorator
def trace(fn):
    def new_fn(*args):
        print(name(fn) + ' called with ' + args_to_string(args))
        result = fn(*args)
        print(name(fn) + ' returns ' + str(result))
        return result
    return new_fn

# Using trace as a decorator.
@trace
def fib(n):
    if n < 2:
        return n
    else:
        return fib(n-1) + fib(n-2)

@trace
def better_fib(n, a=0, b=1):
  if n == 0:
    return a
  else:
    return better_fib(n-1, b, a+b)

# If you uncomment these and run
# python3 10.py
# It will print out the trace.
# Beware:  fib(20) prints out tens of thousands of lines.

# fib(3)
# fib(20)
# better_fib(20)

# Iterative improvement.  Used in Newton's method.
def iter_improve(guess, done, update):
    while not done(guess):
        guess = update(guess)
    return guess

tolerance = 1e-14

def find_zero(f, df, x=1):
    def done(x):
        return abs(f(x)) < tolerance
    def update(x):
        return x - ( f(x) / df(x) )
    return iter_improve(x, done, update)

def sqrt(a):
    return find_zero(lambda x: x*x - a, lambda x: 2*x)

def root(n, a):
    return find_zero(lambda x: pow(x, n) - a, lambda x: n*pow(x, n-1))

dx = 1e-6
def deriv(f):
    def df(x):
        return (f(x + dx) - f(x)) / dx
    return df

def easy_find_zero(f, x=1):
    return find_zero(f, deriv(f), x)

def fixed_point(f):
    return easy_find_zero(lambda x: x - f(x))

def sqrt2(a):
    return fixed_point(lambda x: a / x)

4b03729f438fa5780e70220cbb7a681e06cf101d
<mask token>


def args_to_string(args):
    string = ''
    for arg in args:
        string += str(arg) + ' '
    return string


def trace(fn):

    def new_fn(*args):
        print(name(fn) + ' called with ' + args_to_string(args))
        result = fn(*args)
        print(name(fn) + ' returns ' + str(result))
        return result
    return new_fn


<mask token>


def sqrt(a):
    return find_zero(lambda x: x * x - a, lambda x: 2 * x)


<mask token>


def deriv(f):

    def df(x):
        return (f(x + dx) - f(x)) / dx
    return df


def easy_find_zero(f, x=1):
    return find_zero(f, deriv(f), x)


def fixed_point(f):
    return easy_find_zero(lambda x: x - f(x))


def sqrt2(a):
    return fixed_point(lambda x: a / x)

<mask token>


def args_to_string(args):
    string = ''
    for arg in args:
        string += str(arg) + ' '
    return string


def trace(fn):

    def new_fn(*args):
        print(name(fn) + ' called with ' + args_to_string(args))
        result = fn(*args)
        print(name(fn) + ' returns ' + str(result))
        return result
    return new_fn


<mask token>


def find_zero(f, df, x=1):

    def done(x):
        return abs(f(x)) < tolerance

    def update(x):
        return x - f(x) / df(x)
    return iter_improve(x, done, update)


def sqrt(a):
    return find_zero(lambda x: x * x - a, lambda x: 2 * x)


<mask token>


def deriv(f):

    def df(x):
        return (f(x + dx) - f(x)) / dx
    return df


def easy_find_zero(f, x=1):
    return find_zero(f, deriv(f), x)


def fixed_point(f):
    return easy_find_zero(lambda x: x - f(x))


def sqrt2(a):
    return fixed_point(lambda x: a / x)

def name(fn):
    return fn.__name__


def args_to_string(args):
    string = ''
    for arg in args:
        string += str(arg) + ' '
    return string


def trace(fn):

    def new_fn(*args):
        print(name(fn) + ' called with ' + args_to_string(args))
        result = fn(*args)
        print(name(fn) + ' returns ' + str(result))
        return result
    return new_fn


<mask token>


def find_zero(f, df, x=1):

    def done(x):
        return abs(f(x)) < tolerance

    def update(x):
        return x - f(x) / df(x)
    return iter_improve(x, done, update)


def sqrt(a):
    return find_zero(lambda x: x * x - a, lambda x: 2 * x)


def root(n, a):
    return find_zero(lambda x: pow(x, n) - a, lambda x: n * pow(x, n - 1))


<mask token>


def deriv(f):

    def df(x):
        return (f(x + dx) - f(x)) / dx
    return df


def easy_find_zero(f, x=1):
    return find_zero(f, deriv(f), x)


def fixed_point(f):
    return easy_find_zero(lambda x: x - f(x))


def sqrt2(a):
    return fixed_point(lambda x: a / x)

def name(fn):
    return fn.__name__


def args_to_string(args):
    string = ''
    for arg in args:
        string += str(arg) + ' '
    return string


def trace(fn):

    def new_fn(*args):
        print(name(fn) + ' called with ' + args_to_string(args))
        result = fn(*args)
        print(name(fn) + ' returns ' + str(result))
        return result
    return new_fn


@trace
def fib(n):
    if n < 2:
        return n
    else:
        return fib(n - 1) + fib(n - 2)


@trace
def better_fib(n, a=0, b=1):
    if n == 0:
        return a
    else:
        return better_fib(n - 1, b, a + b)


def iter_improve(guess, done, update):
    while not done(guess):
        guess = update(guess)
    return guess


tolerance = 1e-14


def find_zero(f, df, x=1):

    def done(x):
        return abs(f(x)) < tolerance

    def update(x):
        return x - f(x) / df(x)
    return iter_improve(x, done, update)


def sqrt(a):
    return find_zero(lambda x: x * x - a, lambda x: 2 * x)


def root(n, a):
    return find_zero(lambda x: pow(x, n) - a, lambda x: n * pow(x, n - 1))


dx = 1e-06


def deriv(f):

    def df(x):
        return (f(x + dx) - f(x)) / dx
    return df


def easy_find_zero(f, x=1):
    return find_zero(f, deriv(f), x)


def fixed_point(f):
    return easy_find_zero(lambda x: x - f(x))


def sqrt2(a):
    return fixed_point(lambda x: a / x)

# Black magic to find the name of a function.
def name(fn):
    return fn.__name__

def args_to_string(args):
    string = ''
    for arg in args:
        string += str(arg) + ' '
    return string

# Meant to be used as a decorator
def trace(fn):
    def new_fn(*args):
        print(name(fn) + ' called with ' + args_to_string(args))
        result = fn(*args)
        print(name(fn) + ' returns ' + str(result))
        return result
    return new_fn

# Using trace as a decorator.
@trace
def fib(n):
    if n < 2:
        return n
    else:
        return fib(n-1) + fib(n-2)

@trace
def better_fib(n, a=0, b=1):
  if n == 0:
    return a
  else:
    return better_fib(n-1, b, a+b)

# If you uncomment these and run
# python3 10.py
# It will print out the trace.
# Beware:  fib(20) prints out tens of thousands of lines.

# fib(3)
# fib(20)
# better_fib(20)

# Iterative improvement.  Used in Newton's method.
def iter_improve(guess, done, update):
    while not done(guess):
        guess = update(guess)
    return guess

tolerance = 1e-14

def find_zero(f, df, x=1):
    def done(x):
        return abs(f(x)) < tolerance
    def update(x):
        return x - ( f(x) / df(x) )
    return iter_improve(x, done, update)

def sqrt(a):
    return find_zero(lambda x: x*x - a, lambda x: 2*x)

def root(n, a):
    return find_zero(lambda x: pow(x, n) - a, lambda x: n*pow(x, n-1))

dx = 1e-6
def deriv(f):
    def df(x):
        return (f(x + dx) - f(x)) / dx
    return df

def easy_find_zero(f, x=1):
    return find_zero(f, deriv(f), x)

def fixed_point(f):
    return easy_find_zero(lambda x: x - f(x))

def sqrt2(a):
    return fixed_point(lambda x: a / x)
