---
# System prepended metadata

title: Horner’s method

---

# Horner’s method
When evaluating a polynomial function (1) in a computer program, the naivest way usually result in more computation complexcity.
In order to speed up the process, Horner's scheme were used.
\begin{equation}
    P(x) = a_0 + a_1 x + a_2 x^2 + ... + a_n x^n
    \tag{1}
\end{equation}
Rather than direct evaluating (1), Horner's scheme change (1) into (2) which can give the same result but a more efficient way.
Naive way of evaluating polynomail requires at most $n$ additions and $(n^2+n)/2$ multiplications while Horner's scheme only require $n$ additions and $n$ multiplications.
\begin{equation}
    P(x) = a_0 + x\left(a_1 + x\left(a_2 + x\left(a_3+...+x\left(a_{n-1}+xa_n\right)\right)\right)\right)
    \tag{2}
\end{equation}
Following program first computing the coefficient $a_j$, then I generate a random number using subroutine RANDOM\_NUMBER. Finally, I use another intrinsic function
CPU\_TIME to measure time it takes for two different approach to evaluating the polynomial ($10^5$ times).

## Code
```fortran

!========================================================
!   Purpose: Camparing Horner's scheme with naive way
!
!   Methods: Horner's Method
!       
!       Date        Programer       Description of change
!       ====        =========       =====================
!     8/13/20        MorrisH        Original Code
!========================================================
PROGRAM MAIN
    IMPLICIT NONE
    REAL(8) :: a(100), start, finish, x
    REAL(8) :: NAIVE, HORNER
    INTEGER :: i,

    CALL RANDOM_SEED()
    CALL RANDOM_NUMBER(x)
    open(99, file='naive.dat', status='unknown')
    open(66, file='horner.dat', status='unknown')

    do i = 1, 100, 2
        a(i) = 1.d0 / DBLE(i)
    end do
    do i = 2, 100, 2
        a(i) = -1.d0 / DBLE(i)
    end do

    CALL CPU_TIME(start)
    do i = 1, 100000
        ans = NAIVE(a, x)
    end do
    CALL CPU_TIME(finish)
    ! print *, ans
    ! print '("Naive method cost : ", f7.5, "seconds")', finish-start
    write(99, *) finish-start, ans


    CALL CPU_TIME(start)
    do i = 1, 100000
        ans = HORNER(a, x)
    end do
    CALL CPU_TIME(finish)
    ! print *, ans
    ! print '("Horner method cost : ", f7.5, "seconds")', finish-start
    write(66, *) finish-start, ans

END PROGRAM MAIN

DOUBLE PRECISION FUNCTION NAIVE(a, x)
    IMPLICIT NONE
    REAL(8) :: a(100), x
    INTEGER :: i

    NAIVE = 0.d0
    do i = 1, 100
        NAIVE = NAIVE + a(i) * x ** DBLE(i)
    end do

END FUNCTION NAIVE

DOUBLE PRECISION FUNCTION HORNER(a, x)
    IMPLICIT NONE
    REAL(8) :: a(100), x
    INTEGER :: i

    HORNER = x * a(100)
    do i = 100, 2, -1
       HORNER = (HORNER + a(i-1)) * x 
    end do

END FUNCTION HORNER
```

## Result
I calculate the time it takes for both method to preform $10^5$ times, and divide the time it takes using naive method by the time of evaluating using Horner's method. Naive way cost roughly 7 times longer to calculate in this particular example than Horner's method did. 

![](https://i.imgur.com/BpicvzI.png)


\begin{equation}
    P(x) =  \dfrac{x}{1} + \dfrac{x^2}{2} + ... + \dfrac{x^n}{n}
    = x\left(\dfrac{1}{1}+x\left(\dfrac{1}{2}+x\left(\dfrac{1}{3}+...+x\left(\dfrac{1}{n-1}+x\dfrac{1}{n}\right)\right)\right)\right)
\tag{3}
\end{equation}

For meausering the accuracy, I evaluating (3) from $x=-100$ to $x=100$ using two method. But it seems that the accuracy are roughly the same in this particular example.

![](https://i.imgur.com/mdwd8aT.png)

