Computational Method For Numerical Analysis With R
Computational Method For Numerical Analysis With R
Numerical Analysis Computation with R is an overview of numerical analysis topics using R. This shows
how common topics in numerical analysis such as interpolation, numerical integration, roots of non linear
equation (using bisection method, newton raphson method), finite difference, newton forward and backward
difference, and the likes can be implemented in R. Every algorithm described is given with complete function
implementation in R, along with examples to demostrate the function and its use. This project is working
with the assumption that we all have basic knowledge of topics in numerical analysis, and presume we are
not new to R. So, let’s start with solution to non-linear equation using bisection method.
The bisection method is used to find the root of a countinuous function f (x) on an interval [a, b]. The
principle behind this method is the intermidiate theorem for continuous functions. It works by narrowing
the gap between positive and negative intervals until it closes to the correct answer. This method narrows
the gap by taking the average of the positive and negative intervals.
If a and b are such that f (a) and f (b) have opposite signs, there is at least one root of the equation f (x) = 0
in the interval between a and b (provided f (x) is a continuous function). In the method of bisection, the
midpoint of the interval c = a+b 2 is taken, and from the sign of f (c) it can be deduced whether a root lies
in the half interval to the left or right of c. Whichever half interval is indicated, its midpoint is then taken
and the procedure repeated. This method often requires many iterations, therefore it can be rather slow but
never fails to produce the root. The procedure stops when two values of x are equal to the required degree
of accuracy.
In R, there are two ways of finding the roots of a countinuous function using Bisection Method. One of which
is a function in NLRoot package in R and the other is by writing the algorithm for the bisection method.
To use the BFfzero function in R, we have to install the package NLRoot first, then read the library as
follows.
library(NLRoot)
Example 1
Suppose we are to find the root(s) of the function x3 − 10x + 4 = 0. It is advisable to first plot the function
to know where the root(s) possibly lie(s).
func = function(x){
x^3 - 10*x + 4
}
curve(func, xlim=c(-4,4), col = ’red’, lwd = 2, lty = 2, xlab = "x", ylab = "f(x)")
abline(h=0)
abline(v=0)
1
20
10
f(x)
0
−10
−20
−4 −2 0 2 4
It is obvious from the curve that there are three roots for the function. To find these roots, we use BFfzero
function below in R.
## [1] 1
## [1] -3.345963
## [1] 1.819209e-05
## [1] "finding root is successful"
BFfzero(func, 0, 2)
## [1] 1
## [1] 0.4067291
## [1] -6.637231e-06
## [1] "finding root is successful"
BFfzero(func, 2, 3)
## [1] 1
## [1] 2.939236
## [1] 2.518246e-05
## [1] "finding root is successful"
2
Example 2
We wish to find the root of the function sinx + x − 1 = 0 in this example, We plot the function to find an
interval containing the root(s), as follows:
func2 = function(x){
sin(x) + x - 1
}
curve(func2, xlim=c(-4,4), col = ’red’, lwd = 2, lty=2, xlab = "x", ylab = "f(x)")
abline(h=0)
abline(v=0)
2
1
0
f(x)
−1
−2
−3
−4
−4 −2 0 2 4
library(NLRoot)
BFfzero(func2, 0, 2)
## [1] 1
## [1] 0.5109711
## [1] -4.418654e-06
## [1] "finding root is successful"
Now, we have used the R inbuilt function for the bisection method in finding the root of non-linear equation.
Though, there are inbuilt functions in R for other numerical computation such as Newton-Raphson Method,
Difference Equation, Simpson rule for integration and the likes, our interest is to write a code to define a
function for these numerical computations. Below is the one for bisection method.
3
Bisection <- function(f, a, b, n = 1000, tol = 1e-7) {
if (!(f(a) < 0) && (f(b) > 0)) {
stop(’The root does not exist within this interval’)
} else if (!(f(a) > 0) && (f(b) < 0)) {
stop(’The root does not exist within this interval’)
}
for (i in 1:n) {
c <- (a + b) / 2
if ((f(c) == 0) || ((b - a) / 2) < tol) {
return(c)
}
ifelse(sign(f(c)) == sign(f(a)),
a <- c,
b <- c)
}
print(’Too many iterations’)
}
Now, the function Bisection() is ready to be used, but before that, there is need to define the function to
find its root as follows.
f = function(x){
x^3 - 10*x + 4
}
After defining the function as above,we use the function Bisection(f, a, b) to find its roots. Where a and b
are the points on the curve and f is the defined function f (x).
## [1] -3.345963
Bisection(f, 0, 2)
## [1] 0.4067284
Bisection(f, 2, 3)
## [1] 2.939235
Using this function Bisection(), these roots obtained for f (x) are the same as that of the inbuilt function
BFfzero.
With this, we can use Bisection(f, a, b) to find the root of a defined function in R. Where a and b are the
points on the curve, where there is a change in sign and f is the defined function f (x).
4
2.0 Newton-Raphson Iterative Method
Newton-Raphson iterative method is another way of approximating the root of non-linear continuous func-
tions. It requires the derivative of the function in question and the initial value x0 .
Consider the graph y = f (x), the x - value at point A when the graph crosses the x - axis is given as the
solution of the equation f (x) = 0. If P is the point near to the curve, then x = x0 is an approximated value.
If the intial value (x0 ) of x is known, the value of x1 can be determined, and this process can be repeated
till the root converges at a point. The iterative procedure is defined as
f (xn )
xn+1 = xn −
f 0 (xn )
Suppose we are to find the root of the equation x2 − 5x − 40 = 0, when x0 = 2, the code and the output are
given below.
break(0)
}
x0 = round(x1,4)
print(paste("Iteration" ,n, "is",x0))
}
}
The code above defined the function nrm(f, df, x), where f, df and x are f (x), f 0 (x) and initial value x0
respectively. Now, let’s define the function f (x) and its derivative f 0 (x) as follows.
f = function(x){
z = x^3 - 5*x - 40
return(z)
}
df = function(x){
z = 3*x^2 - 5
return(z)
}
nrm means Newton-Raphson Method. To find the root of a defined function using Newton-Ramphson
Method in R, use nrm(f, df, x)
5
nrm(f, df, 2)
The point of convergence is our root, hence the root of the equation at x0 = 4 is 3.9044 to 4 d.p. To find
other roots of the equation, we use another intial condition x0 , based on the point where there is a change
in sign.
Interpolation may be described as the art of reading between the lines in a table. We are concerned with
obtaining values of a function at some points when the values of the function is known at some other points.
The lagrange interpolating formular is given as:
n
X Lk (x)
Pn (x) = .f (xk )
Lk (xk )
k=0
Here is how we defined a function for Lagrange Interpolation using the interpolating formular above, ‘the
commented code’ here gives a prompt that allow users to input the values to be computed. To make this
happen, uncomment the code and source the code, it will prompt the user to input their own values.
f = 0.0
Lagrange = function(x, y, n, a){
for (i in 1:n){
LX = 1.0
LXk = 1.0
for (j in 1:n){
if(i != j){
LX = LX*(a - x[j])
LXk = LXk*(x[i] - x[j])
}
6
j = j+1
}
f = f + (LX/LXk)*y[i]
i = i+1
}
s = round(f, 4)
print(paste("f(",a,") is ", s))
}
Suppose f (x) = ln(x), and we wish to estimate the value of ln(0.6) from the table below.
x 0.4 0.5 0.7 0.8
y -0.9165 -0.6931 -0.3567 -0.2231
You assign the variables as follows;
But, if the commented codes are ‘uncommented’, there is no need to assign variables, all you need is a
command prompt that allows you to input your variables one after the other.
Now, after assigning the variables, use the function Lagrange(x, y, n, a)
Lagrange(x, y, 4, 0.66)
The output here gives the estimated value of ln(0.66) to be -0.4151 using the given table for lagrange
interpolation. Comparing the result with the actual value of ln(0.66) which is -0.4155, gives a relative error
of 0.096.
The interpolating values can be plotted using:
plot(x,y, col = "green", lwd = 1, pch = 19, xlab = "x", ylab = "f(x)")
yb = approx(x,y, xout = 0.66)
points(0.66, yb$y, col = "red", lwd = 1, pch = 19)
7
−0.3
−0.5
f(x)
−0.7
−0.9
Newton forward difference formular is used to interpolate the values of y that is closer to the beginning of a
set of tabular values. y0 may be taken as any point of the table, but the formular contains only those values
of y which comes after the value chosen as y0 The Newton forward difference formular is given as:
r(r − 1) 2 r(r − 1)(r − 2) 3 r(r − 1)(r − 2)(r − 3) 4
f (x) = y0 + r∆y0 + ∆ y0 + ∆ y0 + ∆ y0 + ...
2! 3! 4!
Where
x = x0 + rh
and
x − x0
r=
h
#n = as.integer(readline(prompt = "Enter n: "))
#x = c(rep(0,n))
#y = c(rep(0,n))
#for(i in 1:n)
#{
# x[i] = as.double(readline(prompt = "Enter x: "))
# y[i] = as.double(readline(prompt = "Enter y: "))
#}
nfd = function(x,y,a){
n = length(x)
A = matrix(c(rep(0,(n-1)^2)), nrow = n-1, ncol = n-1, byrow = TRUE)
8
for (j in 1:(n-1)){
for (i in 1:(n-j))
{
if(j==1)
A[i,j]=(y[i+1]-y[i])
else
A[i,j]=(A[(i+1),(j-1)]-A[i,(j-1)])
}
}
#no = as.integer(readline(prompt = "Enter number to find: "))
u = (a - x[1])/(x[2]-x[1])
print(A)
sum = y[1]
for (i in 1:(n-1))
{
prod = 1
for(j in 0:(i-1))
prod = prod*(u-j)
prod = prod/factorial(i)
sum = sum + prod*A[1,i]
}
print(sum)
}
If the population of a town was given in the table below and we are to estimate the population for year 1895
using Newton forward difference formular,
Year 1891 1901 1911 1921 1931
Population 46 66 81 93 81
then we define the table by assigning Year to x and Population to y as a vector, as shown below.
x = c(1891,1901,1911,1921,1931)
y = c(46,66,81,93,101)
a = 1895
The function nfd(x, y, a) is then used to estimate the population, using the three parameters, where a is
1895.
nfd(x,y,a)
9
5.0 Newton Backward Difference
Newton’s forward difference formular cannot be used for interpolating a value of y near the end of table of
values. For this purpose, we use another formular known as Newton backward difference formular. and it
can be written as:
r(r + 1) 2 r(r + 1)(r + 2) 3 r(r + 1)(r + 2)(r + 3) 4
f (x) = yn + r∇yn + ∇ yn + ∇ yn + ∇ yn + ...
2! 3! 4!
Where
x = x0 + rh
and
x − x0
r=
h
#n = as.integer(readline(prompt = "Enter n: "))
#x = c(rep(0,n))
#y = c(rep(0,n))
#for(ii in 1:n)
#{
# x[ii] = as.double(readline(prompt = "Enter x: "))
# y[ii] = as.double(readline(prompt = "Enter y: "))
#}
nbd = function(x,y,a){
n = length(x)
A = matrix(c(rep(0,(n)^2)), nrow = n, ncol = n, byrow = TRUE)
for (j in 1:(n-1)){
for (i in (j+1):n)
{
if(j==1)
A[i,j]=(y[i]-y[i-1])
else
A[i,j]=(A[(i),(j-1)]-A[(i-1),(j-1)])
}
}
#no = as.integer(readline(prompt = "Enter no to find: "))
u = (a - x[n])/(x[2]-x[1])
print(A)
sum = y[n]
for (i in 1:(n-1))
{
prod = 1
for(j in 0:(i-1))
prod = prod*(u+j)
prod = prod/factorial(i)
sum = sum + prod*A[n,i]
}
print(sum)
}
10
Using same tabular values used for the Newton forward difference, estimate for the year 1925 using Newton
backward difference.
Year 1891 1901 1911 1921 1931
Population 46 66 81 93 81
Following the same procedure as the Newton forward difference, we have:
x = c(1891,1901,1911,1921,1931)
y = c(46,66,81,93,101)
a = 1925
nbd(x,y,a)
Trapezoidal rule is an integration rule that approximates the area under the curve by dividing the total area
into smaller trapezoids, then find the area of the small trapezoids in a definite interval. This rule is used for
approximating the definite integrals where linear approximations of the function are used. There are other
methods of approximating definite integrals, such as Simpson Rule, Rectanglar rule and the likes, which are
going to be discussed later. To calculate the area under the curve using the general trapezoidal rule, we use:
Z b
h
f (x)dx = [(y0 + yn ) + 2(y1 + y2 + y3 + ... + yn−1 )]
a 2
This trapezoidal general formular helps in defining a function for trapezoidal rule approximation for inte-
gration.
trap = function(f,a,b,n){
h = (b-a)/n
x = seq(a, b, by = h)
f = sapply(x, f)
t = h*(f[1]/2 + sum(f[2:n]) + f[n+1]/2)
A = signif(t,4)
print(paste("The integral of f(x) on interval [",a ,"," ,b, "] when n =" ,n ,"is" ,A))
}
11
R7 x3 x3
Suppose we are to approximate the integral 1 1+x4
dx using n = 30, the function f (x) = 1+x4 dx has to be
defined first. To define the function, we use:
f = function(x){
x^3*(1+x^4)^-1
}
The function trap(f,a,b,n) can then be used to approximate the integral of the defined function as follows.
trap(f,1,7,30)
The bigger the n, the greater the degree of accuracy to the actual integral.
Simpson’s Rule is another rule for approximating definite integrals, it converges faster compared to the
Trapezoid rule.
Simpson’s rule is defined as:
Z b
h
f (x)dx = [(y0 + yn ) + 2(y2 + y4 + y6 + ... + yn−2 ) + 4(y1 + y3 + y5 + ... + yn−1 )]
a 3
Where
b−a
h=
n
We can write the function to approximate a definite integral using Simpson’s rule as follows:
simp = function(f,a,b,n){
x[1]=f(a)
x[n+1]=f(b)
h = (b-a)/n
s = f(a) + f(b)
for(i in 1:(n-1))
{
x[i-1]=f(a+i*h)
if(i%%2!=0){
s = s + 4*f(a+i*h)
}
else{
s = s + 2*f(a+i*h)
}
}
I = signif(s*(h/3),4)
print(paste("The integral of f(x) on interval [",a ,"," ,b, "] when n =" ,n ,"is" ,I))
}
12
Using the same function we integrated using trapezoid rule, we have:
f = function(x){
x^3*(1+x^4)^-1
}
simp(f,1,7,30)
Summary
R as an integrated suite that facilitates data manipulation, calculation, mathematical computation and
graphical display. All these have been used as a tool to compute some numerical analysis problems. Algo-
rithms were defined to write functions to compute each numerical method discussed early with examples to
implement the functions in R.
References
G.Shanker Rao (2003). Numerical Analysis (3rd ed.). New Age International Publishers.
Simpson’s rule for integration (2017). In RPubs. Retrieved from https://rpubs.com/aaronsc32/simpsons-
rule-approximate-integrals
Bisection method (2016). In Wikipedia. Retrieved from https://en.wikipedia.org/wiki/Bisection_Method
13