Finding Roots - Advanced (in Python)




Following is the explanation for finding roots (square root, cube root.... nth root) It requires prior knowledge of Bisection Search

This is the advancement of basic version of finding square root of only perfect squares



def findRoot1(x, power, epsilon):
    low = 0
    high = x
    ans = (high+low)/2.0
    while abs(ans**power - x) > epsilon:
        if ans**power < x:
            low = ans
        else:
            high = ans
        ans = (high+low)/2.0
    return ans


Output:
>>> print findRoot1(25.0, 2, .001)
4.99992370605
>>> print findRoot1(27.0, 3, .001)
2.99998855591
>>> print findRoot1(-27.0, 3, .001)

This case fails, it actually gets caught into an infinite loop
What happens is, low = 0 and high = -27, whereas actually 0>-27, so it should be low = -27 and high = 0

So we need to insert a code such that it assigns lower value to low and higher value to high.

def findRoot2(x, power, epsilon):
    if x < 0 and power%2 == 0:
        return None
    # can't find even powered root of negative number
    low = min(0, x) #min() will return the minimum of 0 and x
    high = max(0, x) #max() will return the maximum of 0 and x
    ans = (high+low)/2.0
    while abs(ans**power - x) > epsilon:
        if ans**power < x:
            low = ans
        else:
            high = ans
        ans = (high+low)/2.0
    return ans


Output:
>>> print findRoot2(25.0, 2, .001)
4.99992370605
>>> print findRoot2(27.0, 3, .001)
2.99998855591
>>> print findRoot2(-27.0, 3, .001)
-2.99998855591
>>> print findRoot2(0.25, 2, .001)

This case fails, because when we call with a fractional argument, like 0.25, we are searching between 0 and 0.25

Which means our first guess will be 0.125

Our original idea used the fact that the root of x was between 0 and x, but when x is fractional, the root is between x and 1

So, we have to modify min(0,x) and max(0,x)

def findRoot3(x, power, epsilon):
    if x < 0 and power%2 == 0:
        return None
    # can't find even powered root of negative number
    low = min(-1.0, x) #think of findRoot3(-0.125, 3, .001)
    high = max(1.0, x) #think of findRoot3(0.25, 2, .001)
    ans = (high+low)/2.0
    while abs(ans**power - x) > epsilon:
        if ans**power < x:
            low = ans
        else:
            high = ans
        ans = (high+low)/2.0
    return ans


>>> print findRoot3(25.0, 2, .001)
4.99992370605
>>> print findRoot3(27.0, 3, .001)
2.99998474121
>>> print findRoot3(-27.0, 3, .001)
-2.99998474121
>>> print findRoot3(0.25, 2, .001)
0.5 #sweet
>>> print findRoot3(-0.125, 3, .001)
-0.5


Happy coding.

Eviva.

Note:
This is a part of what I learn in an online Open Course Ware offered by MIT on edX
Its for my personal reference & also for those who have missed the course.
You too can enroll yourself on edX (if they are still offering the course MITx 6.00x)