Horner's Method¶

In this notebook we shall discuss about Horner's method of computing polynomials.
These are the polynomials and the value at which we will be computing these polynomials.

In [1]:
polynomials = [
    ([2, 0, 3, 1], 2),
    ([2, -6, 2, -1], 3),
    ([1, -6, 11, -6], 5),
    ([2,3,-4,1], 10),
]

This is the decorator which will return the time taken by the function to compute the result, along with the result itself

In [2]:
import time as T

def show_time(func):
    def inner(*args, **kwargs):
        start_time = T.time()
        res = func(*args, **kwargs)
        return (res, round((T.time()-start_time)*(10**6),3))
    return inner

Naive Approach¶

In [3]:
@show_time
def naive_calc(arr, x) -> float:
    r = arr[-1]
    m = 1
    i = -2
    n = -len(arr)
    while i >= n:
        m *= x
        r += m * arr[i]
        i -= 1
    return r

Recursive and Iterative approach of Horner's algorithm¶

In [4]:
calc = lambda a, b, x: a * x + b

def rec_compute(arr, x, t, index = 1) -> float:
    r = calc(t, arr[index], x)
    if index == len(arr) - 1:
        return r
    return rec_compute(arr, x, r, index + 1)

@show_time
def rec_compute_caller(arr, x):
    return rec_compute(arr, x, arr[0])

@show_time
def loop_compute(arr, x) -> float:
    i = 0
    r = arr[i]
    while i < (len(arr) - 1):
        r = calc(r, arr[i + 1], x)
        i += 1
    return r

Function to get equation from the coefficient array of the polynomial¶

In [5]:
def updateStringAtIndex(text:str, index:int, char) -> str:
    arr = list(text)
    arr[index] = char
    return ''.join(arr)

def equationFromPol(pol) -> str:
    n = len(pol)
    equation = ""
    for i in pol:
        if i != 0:
            if n == 1:
                if i < 0:
                    equation = updateStringAtIndex(equation,-1,"")
                equation += f"{i}"
            elif n == 2:
                if i == 1: equation += "x"
                elif i== -1:
                    equation = updateStringAtIndex(equation,-1,"-")
                    equation += "x"
                else:
                    if i < 0:
                        equation = updateStringAtIndex(equation,-1,"")
                    equation += f"{i}x+"
            else:
                if i == 1: equation += "x^{%d}+"%(n-1)
                elif i == -1:
                    equation = updateStringAtIndex(equation,-1,"")
                    equation += "x^{%d}+"%(n-1)
                else:
                    if i < 0:
                        equation = updateStringAtIndex(equation,-1,"")
                    equation += "%dx^{%d}+"%(i,n-1)
        n -= 1
    if equation[-1] == "+":
        equation = updateStringAtIndex(equation,-1,"")
    return equation              

Driver code¶

In [6]:
from IPython.display import HTML, display

results = ""

for pol, value in polynomials:
    results += "<tr>"
    
    eq = equationFromPol(pol)
    res1 = naive_calc(pol, value)
    res2 = rec_compute_caller(pol, value)
    res3 = loop_compute(pol, value)
        
    results += f'''
        <td>${eq}$</td>
        <td>{value}</td>
        <td>{res1[0]}</td>
        <td>{res1[1]}</td>
        <td>{res2[0]}</td>
        <td>{res2[1]}</td>
        <td>{res3[0]}</td>
        <td>{res3[1]}</td>
    </tr>
    '''

display(HTML('''<style>
td {
    color: #111827;
    font-weight: 15px;
    text-align: center;
    border: 1px solid black;
}
th {
    color: #e5f4fb;
    background-color: #1971c2;
    text-align: center;
}
tr:nth-child(2n) td{
    background-color: #9aceeb;
}
tr:nth-child(2n+1) td{
    background-color: #88c0d0;
}
.rendered_html tr,
.rendered_html th,
.rendered_html td {
     text-align: center;
     border: 1px solid black;
     font-size: 2rem;
}
</style>
<table>
<thead>
    <tr>
        <th rowspan=2>$p(x)$</th>
        <th rowspan=2>$x$</th>
        <th colspan=2>Naive Method</th>
        <th colspan=2>Horner's Method<br/>(Recursive)</th>
        <th colspan=2>Horner's Method<br/>(Iterative)</th>
    </tr>
    <tr>
        <th>Result</th>
        <th>Time (in ms)</th>
        <th>Result</th>
        <th>Time (in ms)</th>
        <th>Result</th>
        <th>Time (in ms)</th>
    </tr>
</thead>
''' + results + "<table><hr/>"))
$p(x)$ $x$ Naive Method Horner's Method
(Recursive)
Horner's Method
(Iterative)
Result Time (in ms) Result Time (in ms) Result Time (in ms)
$2x^{3}+3x+1$ 2 23 5.484 23 8.106 23 3.815
$2x^{3}-6x^{2}+2x-1$ 3 5 4.53 5 5.007 5 3.576
$x^{3}-6x^{2}+11x-6$ 5 24 2.623 24 2.623 24 2.384
$2x^{3}+3x^{2}-4x+1$ 10 2261 3.099 2261 3.338 2261 2.861