I am always pleased with the capabilities of chebfun (as found on the file exchange.) It seems to have had no problem in finding all 85 roots of that function over the interval of interest.
fun = @(x) 5*sin(1.9*x)+2.1*sin(9.1*x);
roots(chebfun(fun,[0,100]))
As an alternative, one could simply sample the function at a fine interval, looking for any sign changes. Then call fzero on each interval where a sign change was found.
xs = linspace(0,100,1001);
ys = fun(xs);
scinter = find(diff(sign(ys)));
See that there were 85 intervals found where a sign change occurred. I carefully chose code such that the first interval would be found, so fzero will find the zero at 0.
ninter = numel(scinter)
ninter =
85
xroots = NaN(1,ninter);
for i = 1:ninter
xroots(i) = fzero(fun,xs(scinter(i) + [0 1]));
end
Of course, the code above will miss roots that were too close together compared to the discretization interval of 0.1 that I chose. (That is, 1001 steps on the interval [0,100].)
Another code:
fun = @(x)5*sin(1.9*x)+2.1*sin(9.1*x);
t = 0:.01:100;
for ii = 1:length(t)
yy(ii) = fzero(fun,t(ii));
end
zz = unique(yy);
zz = sort(zz);
z = round(1e9*zz)*1e-9; % Get rid of spurious differences
z = unique(z);
q = find(z>100);
z(q) = [];
% code
s = sign(y);
s(isnan(s))=[];
rr = find(sign(y)==0); %look up for machine number zeros
r = find(([s(1) s]==[s s(end)])==0); %look up for nearby machine number zeros
if isempty(rr)
return
else
r((rr+1)==r)=[]; %get rid of duplicities
r((rr-1)==r)=[];
end
I. Newton’s Method or Newton--Raphson Method
The following iterative method, named after the English mathematicians
Isaac Newton (1642--1726) and
Joseph Raphson
(1648--1715), used for solving the equation
f(
x) = 0:
\[
x_{k+1} = x_k - \frac{f(x_k)}{f' (x_k )} , \qquad k=0,1,2,\ldots .
\]
|
III. Newton’s Method or Newton--Raphson Method
The following iterative method, named after English mathematicians Isaac Newton (1642--1726) and Joseph Raphson (1648--1715), used for solving the equation
f(x) = 0:
\[
p_{k+1} = p_k - \frac{f(p_k)}{f' (p_k )} , \qquad k=0,1,2,\ldots .
\]
The basic idea behind Newton's method is quite straightforward. Let
pn denote the most recent approximation to zero,
p, of the function
f. Replace
f by its tangent line appriximation that goes through the point
pn and takes the abscissa-intercept of the tangent line as the next approximation
pn+1 to the root. ■
When Newton's method is applied to find a square root of a positive number
A, we get the Babylonian formula
\[
p_{k+1} = \frac{1}{2} \left( p_k + \frac{A}{p_k} \right) , \qquad k=0,1,2,\ldots .
\]
Ancient Mesopotamia was a civilization that existed in the area of modern Turkey, Syria, Iraq and Iran, between the Mediterranean Sea and the Persian Gulf. In the period 1900--1600 BC, Babylon was the capital city of Mesopotamia and the mathematics recorded at this time came to be known as Babylonian Mathematics.
The Babylonians had an accurate and simple method for finding the square roots of numbers. This method is also known as Heron's method, after the Greek mathematician who lived in the first century AD. Indian mathematicians also used a similar method as early as 800 BC. The Babylonians are credited with having first invented this square root method, possibly as early as 1900 BC.
Example. We use Newton's method to find a positive square root of 6. Starting with one of the two initial positions, we get
\begin{align*}
p_0 &=2, \quad &p_0 =3.5 , \\
p_1 & = \frac{5}{2} = 2.5, \quad &p_1 = 2.60714, \\
p_2 &= \frac{49}{20} ={\bf 2.4}5 , \quad &p_2 = {\bf 2.4}5426 , \\
p_3 &= \frac{4801}{1960} \approx {\bf 2.4494897}, \quad &p_3 = {\bf 2.4494}943716069653 , \\
p_4 &= \frac{46099201}{18819920} \approx {\bf 2.44948974278317}9 , &p_4 = {\bf 2.44948974278}75517, \\
p_5 &= \frac{4250272665676801}{1735166549767840} \approx {\bf 2.449489742783178} , & p_5 = {\bf 2.449489742783178}.
\end{align*}
As we see it converges pretty fast. In fact, this method converges quadratically---the number of correct decimal places approximately doubles with every step!
p[0] = 2
Do[Print["k= ", k, " " , "p= " ,
p[k] = (p[k - 1] + 6/p[k - 1])/2], {k, 1, 5}]
We can convert the square root problem to a fixed point iteration:
\[
p_{k+1} = \frac{p_k +6}{p_k +1} , \qquad k=0,1,2,\ldots ;
\]
which converges to
\( \sqrt{6} = 2.449489742783178\ldots , \) but very slowly. However, another suggested iteration
\[
p_{k+1} = 3\,\frac{p_k^2 -1}{2\,p_k} , \qquad k=0,1,2,\ldots ;
\]
diverges.
Theorem: Let f be twice continuously differentiable function on the interval [a,b] with \( p \in \left( a, b \right) \quad\mbox{and} \quad f(p) =0 . \) Suppose that \( f' (p) \ne 0. \) Then there exists a positive number δ such that for any \( p_0 \in \left[ p - \delta , p+\delta \right] , \) the sequence \( \left\{ p_n \right\} \) generated by Newton's algorithm converges to p. ■
Sometimes Newton’s method does not converge; the above theorem guarantees that δ exists under certain conditions, but it could be very small. Newton's method is a good way of approximating solutions, but applying it requires some intelligence. You must beware of getting an unexpected result or no result at all. So why would Newton’s method fail? Well, the derivative may be zero at the root; the function may fail to be continuously differentiable; one of the iterated points xn is a local minimum/maximum of f; and you may have chosen a bad starting point, one that lies outside the range of guaranteed convergence. Depending on the context, each one of these may be more or less likely. Degenerate roots (those where the derivative is 0) are "rare" in general and we do not consider this case.
Finally, there is a chance that Newton's method will cycle back and forth between two value and never converge at all. This failure is illustrated in Figure below.
a1 = {Arrowheads[Medium], Arrow[{{2.5, 6.875}, {3.5, 4}}]}
a2 = {Arrowheads[Medium], Arrow[{{3.5, 7.125}, {2.5, 4}}]}
b1 = Graphics[{Dashed, Red, a1}]
b2 = Graphics[{Dashed, Blue, a2}]
f[x_] = x^3 - 5*x^2 + 3.05*x + 15
graph = Plot[f[x], {x, 0.5, 4}, PlotRange -> {4, 16}, PlotStyle -> Thick]
v1 = {Arrowheads[Medium], Arrow[{{2.5, 4}, {2.5, 6.875}}]}
v2 = {Arrowheads[Medium], Arrow[{{3.5, 4}, {3.5, 7.125}}]}
b11 = Graphics[{Dashed, Red, v1}]
b22 = Graphics[{Dashed, Blue, v2}]
Show[graph, b1, b2, b11, b22]
For example, take a function
\( f(x) = x^2 -2x +1 \) and let start with
x0 =0. The first iteration produces 1 and the second iteration returns back to 0, so the
sequence will oscillate between the two without converging to a root.
function [p0, err, k, y] = newton(f,df,p0,delta,epsilon,max1)
% Input: f is the object function input as a sring 'f'
% df is the derivative of f input as a string 'df'
% p0 is the initial approximation to a zero of f
% delta is the tolerance for p0
% epsilon is the tolerance for the function values y
% max1 is the maximum number of iterations
% Output: p0 is the Newton--Raphson approximation to the zero/null
% k is the number of iterations
% err is the error estimate for p0
% y is the function value f(p0)
for k=1:max1
p1=p0-feval(f,p0)/feval(df,p0);
err=abs(p1-p0);
relerr=2*err/(abs(p1)+delta);
p0=p1;
y=feval(f,p0);
if (err < delta)|(relerr < delta)|(abs(y) < epsilon),break,end
end
function [ x, ex ] = newton( f, df, x0, tol, nmax )
% Input:
% f - input funtion
% df - derived input function
% x0 - inicial aproximation
% tol - tolerance
% nmax - maximum number of iterations
%
% Output:
% x - aproximation to root
% ex - error estimate
%
% Example:
% [ x, ex ] = newton( 'exp(x)+x', 'exp(x)+1', 0, 0.5*10^-5, 10 )
if nargin == 3
tol = 1e-4;
nmax = 1e1;
elseif nargin == 4
nmax = 1e1;
elseif nargin ~= 5
error('newton: invalid input parameters');
end
f = inline(f);
df = inline(df);
x(1) = x0 - (f(x0)/df(x0));
ex(1) = abs(x(1)-x0);
k = 2;
while (ex(k-1) >= tol) && (k <= nmax)
x(k) = x(k-1) - (f(x(k-1))/df(x(k-1)));
ex(k) = abs(x(k)-x(k-1));
k = k+1;
end
end
Another code:
f = @(x) x + x^(4/3); % Equation definition!
fp = @(x) 1 + 4/3*x^(1/3); % First-order derivative of f!
x0 = 1; % Initial guess
N = 10; % Maximum number of iterations
tol = 1E-6; % Convergence tolerance
x = zeros(N + 1,1); % Preallocate solution vector where row => iteration
x(1) = x0; % Set initial guess!
% Newton's Method algorithm
n = 2;
nfinal = N + 1; % Store final iteration if tol is reached before N iterations!
while (n <= N + 1)
fe = f(x(n - 1));
fpe = fp(x(n - 1));
x(n) = x(n - 1) - fe/fpe;
if (abs(fe) <= tol)
nfinal = n; % Store final iteration
break;
end
n = n + 1;
end
% Plot evolution of the solution
figure('Color','White')
plot(0:nfinal - 1,x(1:nfinal),'o-')
title('Newton''s Method Solution: $f(x) = x + x^{\frac{4}{3}}$','FontSize',
20,'Interpreter','latex')
xlabel('Iteration','FontSize',16)! ylabel('$x$','FontSize',16,'Interpreter','latex')
function newton(r);
syms x;
y = exp(x) - 1.5 - atan(x);
yprime = diff(y,x);
f = matlabFunction(y);
fprime = matlabFunction(yprime);
x = r;
xvals = x
for i=1:8
u = x;
x = u - f(u)/fprime(u);
xvals = x
end
Another code:
function NewtonRaphsonMethod
%Implmentaton of Newton-Raphson method to determine a solution.
%to approximate solution to x = cos(x), we let f(x) = x - cos(x)
i = 1;
p0 = 0.5*pi; %initial conditions
N = 100; %maximum number of iterations
error = 0.0001; %precision required
syms 'x'
f(x) = x - cos(x); %function we are solving
df = diff(f); %differential of f(x)
while i <= N
p = p0 - (f(p0)/df(p0)); %Newton-Raphson method
if (abs(p - p0)/abs(p)) < error %stopping criterion when difference between iterations is below tolerance
fprintf('Solution is %f \n', double(p))
return
end
i = i + 1;
p0 = p; %update p0
end
fprintf('Solution did not coverge within %d iterations at a required precision of %d \n', N, error) %error for non-convergence within N iterations
end
Example. Consider the function \( f(x) = x\,e^{-x^2} \) that obviously has a root at x = 0. However, if your starting point exceeds the root of the equation \( f'(x) = 0 , \) which is \( x_0 = 1/\sqrt{2} \approx 0.707107 , \) than Newton's algorithm diverges.
f[x_]= x*Exp[-x^2]
D[x*Exp[-x^2], x]
FindRoot[E^-x^2 - 2 E^-x^2 x^2 == 0, {x, 1}]
Plot[x*Exp[-x^2], {x, -3, 3}, PlotStyle -> Thick, PlotLabel -> x*Exp[-x^2]]
p[0] = 0.8
Do[Print["k= ", k, " " , "p= " ,
p[k] = p[k - 1] - p[k - 1]/(1 - 2*p[k - 1])], {k, 1, 15}]
Newton's method diverges for the cube root, which is continuous and
infinitely differentiable, except for
x = 0, where its derivative is undefined:
\[
x_{k+1} = x_k - \frac{x_k^{1/3}}{(1/3)\,x_k^{-2/3}} = -2\,x_k , \qquad k=0,1,2,\ldots ;
\]
k = 0;
while abs(x - xprev) > eps*abs(x)
xprev = x;
x = x - f(x)/fprime(x)
k = k + 1;
end
Square root:
while abs(x - xprev) > eps*abs(x)
xprev = x;
x = 0.5*(x + M/x);
end
In this section, we consider a problem of finding root of the equation
\( f(x) =0 \) for sufficiently smooth function
f(x). If this equation has a solution, it is called a zero/null of the function
f. Every rootfinding problem can be transformed into any number
of fixed point problems. Consider the following example.
Example. Let \( f(x) = x^5 -5x+3 \) and we try to find its null, so we need to solve the equation \( x^5 -5x+3 =0 . \) Mathematica provides two real positive roots:
FindRoot[x^5 - 5 x + 3 == 0, {x, 0.5}]
Out[1]= {x -> 0.618034}
FindRoot[x^5 - 5 x + 3 == 0, {x, 1.5}]
Out[2]= {x -> 1.27568}
Solving for
x, we convert the original equation into
\[
x = \frac{x^5 +3}{5} \qquad \Longrightarrow \qquad x_{k+1} = \frac{x^5_k +3}{5} , \qquad k=1,2,\ldots .
\]
When you try the starting point
\( x_0 = 0.5 , \) the fixed point iteration will provide you a very good approximation to the null
x = 0.618034. However, when you start with
\( x_0 = 1.5 , \) the fixed point iteration will diverge.
Let us add and subtruct x from the equation: \( x^5 -5x+3+x =x . \) Expressing x, we derive another fixed point formula
\[
x = x^5 -4x +3 \qquad \Longrightarrow \qquad x_{k+1} = x^5_k -4x_k +3 , \qquad k=1,2,\ldots .
\]
Whatever the starting point was chosen, the above fixed point iteration diverges. ■
The formula involved in the secant method is very close to the one used in regula falsi:
\[
p_{k+1} = p_k - \frac{f(p_k ) \left( p_k - p_{k-1} \right)}{f (p_k ) - f(p_{k-1} )} , \qquad k=1,2,\ldots .
\]
When secant method is applied to find a square root of a positive number
A, we get the formula
\[
p_{k+1} = p_k - \frac{p_k^2 -A}{p_k + p_{k-1}} , \qquad k=1,2,\ldots .
\]
Example. Let us find a positive square root of 6. To start secant method, we need to pick up two first approximations,which we choose by obvious bracketing: \( x_0 =2, \quad x_1 =3 . \)
\begin{align*}
x_2 &= 3 - \frac{9-6}{3+2} = \frac{12}{5} =2.4 , \\
x_3 &= 2.4 - \frac{2.4^2 -6}{2.4+3} = \frac{22}{9} = 2.44444 , \\
x_4 &= \frac{22}{9} - \frac{(22/9)^2 -6}{22/9 + 12/5} = \frac{267}{109} \approx 2.44954 , \\
\vdots & \quad \vdots , \\
x_9 &= \frac{1691303970864713862076027918}{690471954760262617049295761} \approx 2.449489742783178 ,
\end{align*}
which is a number with 16 correct decimal places.
function [p1, err, k, y] = secant(f,p0,p1,delta,epsilon,max1)
% Input: f is the object function input as a sring 'f'
% p0 and p1 are the initial approximations to a zero
% delta is the tolerance for p1
% epsilon is the tolerance for the function values y
% max1 is the maximum number of iterations
% Output: p1 is the secant method approximation to the zero/null
% k is the number of iterations
% err is the error estimate for p1
% y is the function value f(p1)
for k=1:max1
p2=p1-feval(f,p1)*(p1-p0)/(feval(f,p1)-feval(f,p0));
err=abs(p2-p1);
relerr=2*err/(abs(p2)+delta);
p0=p1;
p1=p2;
y=feval(f,p1);
if (err < delta)|(relerr < delta)|(abs(y) < epsilon),break,end
end
%% It will take function and initial value as the input of function.
% You would require to run it in command window as
% secant (@(x)(x^2 + x -9),2,3.5,0.001)
% where x^2 + x -9 is function, [2,3] initial values and 0.001 is maximum
% error tolerable.
function y = secant(f,a,b,maxerr)
c = (a*f(b) - b*f(a))/(f(b) - f(a));
disp(' Xn-1 f(Xn-1) Xn f(Xn) Xn+1 f(Xn+1)');
disp([a f(a) b f(b) c f(c)]);
while abs(f(c)) > maxerr
a = b;
b = c;
c = (a*f(b) - b*f(a))/(f(b) - f(a));
disp([a f(a) b f(b) c f(c)]);
flag = flag + 1;
if(flag == 100)
break;
end
end
display(['Root is x = ' num2str(c)]);
y = c;
Another code:
function c = secant(x0, x1, delta)
%% Remember that the function statement must be at the top of
%% your m-file! Comments come after the function statement.
%%
%% secant.m
%%
%% Implements the secant method
%%
%% Input: x0 initial guess for the root of f
%% x1 another initial guess for the root of f
%% delta the tolerance/accuracy we desire
%%
%% Output: c the approxmiation to the root of f
%%
%% Syntax: secant(x0, x1, delta)
%%
%% Notes:
%% 1. Don't use eps as a variable. eps is an internal
%% MATLAB routine in some versions of MATLAB.
%% 2. The code defining f comes after the code
%% defining secant, since secant depends on f.
%% 3. By default, MATLAB only displays 5 digits. You can
%% change this by issuing the command "format long e".
%% See "help format" for more details.
%%
format long e
fx0 = f(x0);
fx1 = f(x1);
if abs(fx1) < abs(fx0), %% c is the current best approx to a root.
c = x1; fc = fx1;
else
c = x0; fc = fx0;
end;
fprintf('initial guesses: x0=%d, x1=%d, fx0=%d, fx1=%d\n',x0,x1,fx0,fx1)
if abs(fc) <= delta %% check to see if initial guess satisfies
return; %% convergence criterion.
end;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% %%
%% main routine %%
%% %%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
while abs(fc) > delta,
fpc = (fx1-fx0)/(x1-x0); %% this is the secant approx to f'.
if fpc==0, %% if fprime is 0, abort.
error('fprime is 0') %% the error function prints message and exits
end;
x0 = x1; fx0 = fx1; %% save previous iterate
x1 = x1 - fx1/fpc; %% secant step
fx1 = f(x1);
if abs(fx1) < abs(fx0), %% store best approx to root in c.
c = x1; fc = fx1;
else
c = x0; fc = fx0;
end;
fprintf(' x0=%d, x1=%d, fx0=%d, fx1=%d\n',x0,x1,fx0,fx1)
end;
%% put subroutines here
function fx = f(x)
fx = (5-x)*exp(x) - 5;
return;
Another code:
function SecantMethod
%SecantMethod example
%to approximate solution to x = cos(x), we let f(x) = x - cos(x)
error = 0.0001; %predefine some tolerance.
N = 100; %number of steps
i = 2;
p0 = 2; %the two guesses
p1 = 1;
syms 'x'
f(x) = x^2 - 6; %what we are solving for f(x) = 0
q0 = f(p0); %two coressponding values of the function evaluated at po and p1
q1 = f(p1);
while i <= N
p = p1 - (q1*((p1 - p0)/(q1 - q0))); %actual Secant Method (finds x axis intercept between two guesses)
if abs(p - p1) < error %stopping criterion
fprintf('Solution is %f \n', double(p))
return
end
i = i + 1;
p0 = p1; %update all the new parameters, po, p1, q0, q1
p1 = p;
q0 = q1;
q1 = f(p);
end
fprintf('Solution did not converge within %d iterations \n', N)
end
Taken from Cleve Moler
https://blogs.mathworks.com/cleve/2015/10/12/zeroin-part-1-dekkers-algorithm/
f = @(x) 1./(x-3)-6;
ezplot(f,[3,4])
hold on
plot(3+1/6,0,'ro')
set(gca,'xtick',[3:1/6:4])
hold off
Bisection
Dekker's algorithm needs to start with an interval [a,b]
on which the given function f(x) changes sign. The notion of a continuous function of a real variable becomes a bit elusive in floating point arithmetic, so we set our goal to be finding a much smaller subinterval on which the function changes sign. I have simplified the calling sequence by eliminating the tolerance specifying the length of the convergence interval. All of the following functions iterate until the length of the interval [a,b] is of size roundoff error in the endpoint b
Secant method
If we have two iterates a
and b, with corresponding function values, whether or not they exhibit a sign change, we can take the next iterate to be the point where the straight line through [a,f(a)] and [b,f(b)] intersects the x
-axis. This is the secant method. Here is the code, with the computation of the secant done carefully to avoid unnecessary underflow or overflow. The trouble is there is nothing to prevent the next point from being outside the interval.
type secant
function b = secant(f,a,b)
s = '%5.0f %19.15f %23.15e\n';
fprintf(s,1,a,f(a))
fprintf(s,2,b,f(b))
k = 2;
while abs(b-a) > eps(abs(b))
c = a;
a = b;
b = b + (b - c)/(f(c)/f(b) - 1);
k = k+1;
fprintf(s,k,b,f(b))
end
secant(f,3.1,3.5)
Secant:
while abs(b-a) > eps*abs(b)
c = a;
a = b;
b = b + (b - c)/(f(c)/f(b)-1);
k = k + 1;
end
http://www.sci.utah.edu/~beiwang/teaching/cs6210-fall-2016/zeros.pdf
III. Steffensen's Iteration Method
IV. Chebyshev Iteration Scheme
IV. Chebyshev Iteration Scheme
The Chebyshev iteration is an iterative method for determining the solutions of a system of linear equations
\( f(x) =0. \) The method is named after Russian mathematician Pafnuty Chebyshev (1821--1894), who discoved it in 1838 as a student project (but not published until 1951).
\[
x_{k+1} = x_k - \frac{f( x_k )}{f' (x_k )} - \frac{f(x_k ) \, f'' (x_k )}{2\left( f' (x_k ) \right)^3} , \qquad k=0,1,2,\ldots .
\]
When Chebyshev iteration scheme is applied to solve a quadratic equation
\( x^2 -A =0, \) it leads to
\[
p_{k+1} = \frac{1}{2} \left( p_k + \frac{A}{p_k} \right) - \frac{\left( p_k^2 -A \right)^2}{8\,p_k^3} , \qquad k=0,1,2,\ldots .
\]
Example. Let us reconsider the problem of determination of a positive square root of 6 using Chebyshev iteration scheme:
\[
p_{k+1} = \frac{1}{2} \left( p_k + \frac{6}{p_k} \right) - \frac{\left( p_k^2 -6 \right)^2}{8\,p_k^3} , \qquad k=0,1,2,\ldots .
\]
\begin{align*}
p_0 &=2, \qquad &p_0 =3, \\
p_1 &= \frac{39}{16} = 2.4375 , \quad &p_1 = \frac{59}{24} \approx 2.4583\overline{3} , \\
p_2 &= \frac{2066507}{843648} \approx {\bf 2.449489}597557 , \quad & p_2 = \frac{32196721}{13144256} \approx {\bf 2.4494897}999 , \\
p_3 &= \frac{48631344989193667537677361}{19853663454796665627720704} \approx {\bf 2.449489742783178}, \quad &p_3 = \frac{8596794666982120560353042061123}{3509626726264305284645257635328} \approx {\bf 2.449489742783178} .
\end{align*}
p[0] = 2
Do[Print["k= ", k, " " , "p= " ,
p[k] = (p[k - 1] + 6/p[k - 1])/
2 - (p[k - 1]^2 - 6)^2/(8*p[k - 1]^3)], {k, 1, 5}]
So we see that the third iteration gives an approximation with 16 correct decimal places.
Matlab code:
function [x] = SolChebyshev002(A, b, x0, iterNum, lMax, lMin)
d = (lMax + lMin) / 2;
c = (lMax - lMin) / 2;
preCond = eye(size(A)); % Preconditioner
x = x0;
r = b - A * x;
for i = 1:iterNum % size(A, 1)
z = linsolve(preCond, r);
if (i == 1)
p = z;
alpha = 1/d;
else if (i == 2)
beta = (1/2) * (c * alpha)^2
alpha = 1/(d - beta / alpha);
p = z + beta * p;
else
beta = (c * alpha / 2)^2;
alpha = 1/(d - beta / alpha);
p = z + beta * p;
end;
x = x + alpha * p;
r = b - A * x; %(= r - alpha * A * p)
if (norm(r) < 1e-15), break; end; % stop if necessary
end;
end
The English astronomer, geophysicist, mathematician, meteorologist, and physicist Edmund/Edmond
Halley (1656--1741) discovered in 1694 the following iteration algorithm for solving the equation
f(
x) = 0:
\[
x_{k+1} = x_k - \frac{2\,f \left( x_k \right) f' \left( x_k \right)}{2\left( f' \left( x_k \right)\right)^2 - f \left( x_k \right) f'' \left( x_k \right) }
, \qquad k=0,1,2,\ldots .
\]
|
The iteration algrithm above is called the
Halley's method.
Edmund is well known for first predicting the orbit of the comet that bears his name. Usually Halley's formula, which is of the third order, makes the convergence of the process of iteration extremely rapid when the first approximation is fairly close to the null. For example, application of Halley's method to solving the quadratic equation
\( x^2 -A =0 \) leads to the recurrence
\[
x_{k+1} = x_k - \frac{2x_k \left( x_k^2 -A \right)}{3x_k^2 +A} , \qquad k=0,1,2,\ldots ;
\]
V. Halley's Method
The English astronomer, geophysicist, mathematician, meteorologist, and physicist Edmund/Edmond Halley (1656--1741) discovered the following iteration algorithm
\[
x_{k+1} = x_k - \frac{f( x_k )}{f' (x_k ) - \frac{f(x_k ) \, f'' (x_k )}{2\, f' (x_k )}} , \qquad k=0,1,2,\ldots ;
\]
in 1694. He is well known for first predicting the orbit of the comet that bears his name. Usually Halley's formula makes the convergence of the process of iteration extremely rapid when the first approximation is fairly close to the null. For example, application of Halley's method to solving the quadratic equation
\( x^2 -A =0 \) leads to the recurrence
\[
x_{k+1} = x_k - \frac{2x_k \left( x_k^2 -A \right)}{3x_k^2 +A} , \qquad k=0,1,2,\ldots ;
\]
Example. Let us find a few iterations for determination of a square root of 6:
\begin{align*}
p_0 &=2, \qquad &p_0 =3, \\
p_1 &= \frac{22}{9} \approx 2.4\overline{4} , \quad &p_1 = \frac{27}{11} \approx 2.45\overline{45} , \\
p_2 &= \frac{21362}{8721} \approx {\bf 2.4494897}37 , \quad & p_2 = \frac{26163}{10681} \approx {\bf 2.44948974}81 , \\
p_3 &= \frac{19496458483942}{7959395846169} \approx {\bf 2.449489742783178}, \quad &p_3 = \frac{23878187538507}{9748229241971} \approx {\bf 2.449489742783178} .
\end{align*}
p[0] = 2
Do[Print["k= ", k, " " , "p= " ,
p[k] = p[k - 1] -
2*p[k - 1]*(p[k - 1]^2 - 6)/(3*p[k - 1]^2 + 6)], {k, 1, 5}]
So we see that the third iteration gives an approximation with 16 correct decimal places.
function HalleysMethod
%Halley's Method invloves: g(x) = x - f(x)/f'(x)*[1 - f(x)f''(x)/(2(f'(x))^2)
%f(x) = x^2 - 6.
i = 1;
p0 = 1; %initial conditions
N = 100; %maximum number of iterations
error = 0.00000001; %precision required
syms 'x'
f(x) = x^2 - 6; %the function we are root finding.
dx = diff(f); %first and second derivatives of f(x)
ddx = diff(dx);
while i <= N
p = p0 - (f(p0)/dx(p0))*(1 - (f(p0)*ddx(p0)/dx(p0)^2))^(-1); %Implementation og Halleys Methof (i.e. g(x)).
if (abs(p - p0)/abs(p)) < error %stopping criterion when difference between iterations is below tolerance
fprintf('Solution is %f \n', double(p))
return
end
i = i + 1;
p0 = p; %update p0
end
fprintf('Solution did not coverge within %d iterations at a required precision of %d \n', N, error) %error for non-convergence within N iterations
end
matlab code for the inverse function
f = @(x) 1./(x-3)-6;
ezplot(f,[3,4])
hold on
plot(3+1/6,0,'ro')
set(gca,'xtick',[3:1/6:4])
hold off
interval [a,b]
if f(a) < f(b): swap(a,b)
c:=a
mflag=true
repeat
if fa!=fc && fb!=fc:
fa=f(a)
fb=f(b)
fc=f(c)
s=(a*fb*fc)/((fa-fb)*(fa-fc))+(b*fa*fc)/((fb-fc)*(fb-fa))+(c*fa*fb)/((fc-fa)*(fc-fb))
else if fa==fc:
x=f(b)
y=f(a)
s=b-((x*(b-a))/(x-y)
if( (condition 1) s is not between (3a+b)/4 and b or
(condition 2) (mflag is set and |s−b| ≥ |b−c|/2) or
(condition 3) (mflag is cleared and |s−b| ≥ |c−d|/2) or
(condition 4) (mflag is set and |b−c| < |tolerance|) or
(condition 5) (mflag is cleared and |c−d| < |tolerance|) then):
s=bisection()
mflag=true
else
mflag=false
replace a,b,c, using old a,b,c,s
until |b-a|
The following matlab code is taken from
https://blogs.mathworks.com/cleve/2015/10/12/zeroin-part-1-dekkers-algorithm/
and it is function zeroin:
%% ZEROIN, Part 1: Dekker's Algorithm
% Th. J. Dekker's _zeroin_ algorithm from 1969 is one of my favorite algorithms.
% An elegant technique combining bisection and the secant method for finding
% a zero of a function of a real variable, it has become |fzero| in MATLAB
% today. This is the first of a three part series.
%% Dirk Dekker
% I have just come from the
% , organized by the
% Dutch/Flemish _Werkgemeenschap Scientific Computing_ group.
% One of the special guests was Th. J. "Dirk" Dekker, a retired professor
% of mathematics and computer science at the University of Amsterdam.
%%
% In 1968 Dekker, together with colleague Walter Hoffmann, published a two-part
% report from the Mathematical Centre in Amsterdam, that described a
% comprehensive library of Algol 60 procedures for matrix computation.
% This report preceded by three years the publication of the Wilkinson and
% Reinsch _Handbook for Automatic Computation, Linear Algebra_ that
% formed the basis for EISPACK and eventually spawned MATLAB.
%% Zeroin in Algol
% Dekker's program for computing a few of the eigenvalues of a real
% symmetric tridiagonal matrix involves Sturm sequences and calls a utility
% procedure, _zeroin_. Here is a scan of _zeroin_ taken from Dekker's
% 1968 Algol report. This was my starting point for the MATLAB code
% that I am about to describe.
%
% <>
%
%%
% Dekker presented _zeroin_ at a conference whose proceedings were edited
% by B. Dejon and Peter Henrici. Jim Wilkinson described a similar algorithm
% in a 1967 Stanford report. Stanford Ph. D. student Richard Brent made
% important improvements that I will describe in my next blog post.
% Forsythe, Malcolm and I made Brent's work the basis for the Fortran
% zero finder in _Computer Methods for Mathematical Computations_.
% It subsequently evolved into |fzero| in MATLAB.
%% The test function
% Here is the function that I will use to demonstrate _zeroin_.
%
% $$ f(x) = \frac{1}{x-3}-6 $$
%
f = @(x) 1./(x-3)-6;
ezplot(f,[3,4])
hold on
plot(3+1/6,0,'ro')
set(gca,'xtick',[3:1/6:4])
hold off
%%
% This function is intentionally tricky. There is a pole at $x = 3$ and
% the zero we are trying to find is nearby at $x = 3 \frac{1}{6}$. The
% only portion of the real line where the function is positive is on the
% left hand one-sixth of the above $x$-axis between these two points.
%% Bisection
% Dekker's algorithm needs to start with an interval $[a,b]$ on which
% the given function $f(x)$ changes sign. The notion of a continuous
% function of a real variable becomes a bit elusive in floating point
% arithmetic, so we set our goal to be finding a much smaller subinterval
% on which the function changes sign.
% I have simplified the calling sequence by eliminating the tolerance
% specifying the length of the convergence interval. All of the following
% functions iterate until the length of the interval $[a,b]$ is of size
% roundoff error in the endpoint $b$.
%%
% The reliable, fail-safe portion of _zeroin_ is the bisection algorithm.
% The idea is to repeatedly cut the interval $[a,b]$ in half,
% while continuing to span a sign change. The actual function values are
% not used, only the signs. Here is the code for bisection by itself.
type bisect
%%
% Let's see how |bisect| performs on our test function.
% The interval |[3,4]| provides a satisfactory starting interval
% because IEEE floating point arithmetic generates a properly signed infinity,
% |+Inf|, at the pole.
bisect(f,3,4)
%%
% You can see the length of the interval being cut in half in the
% early stages of the |x| values and then the values of |f(x)| being cut
% in half in the later stages. This takes 53 iterations. In fact, with
% my stopping criterion involving |eps(b)|, if the starting |a| and |b| are
% of comparable size, |bisect| takes 53 iterations for _any_ function
% because the double precision floating point fraction has 52 bits.
%%
% Except for some cases of pathological behavior near the end points that
% I will describe in my next post, bisection is guaranteed to converge.
% If you have a starting interval with a sign change, this algorithm will
% almost certainly find a tiny subinterval with a sign change. But it is
% too slow. 53 iterations is usually too many. We need something that takes
% many fewer steps.
%% Secant method
% If we have two iterates $a$ and $b$, with corresponding function values,
% whether or not they exhibit a sign change, we can take the next iterate
% to be the point where the straight line through $[a,f(a)]$ and $[b,f(b)]$
% intersects the $x$ -axis. This is the secant method. Here is the code,
% with the computation of the secant done carefully to avoid unnecessary
% underflow or overflow. The trouble is there is nothing to prevent the next
% point from being outside the interval.
type secant
%%
% A secant through the point at infinity does not make sense, so we have to
% start with a slightly smaller interval, but even this one soon gets into
% trouble.
secant(f,3.1,3.5)
%%
% This shows the secant method can be unreliable. At step 4 the secant
% through the previous two points meets the $x$ -axis at $x = 2.9$ which
% is already outside the initial interval. By step 10 the iterate has
% jumped to the other branch of the function. And at step 12 the computed
% values exceed my output format.
%%
% Interestingly, if we reverse the roles of $a$ and $b$ in this case,
% |secant| does not escape the interval.
secant(f,3.5,3.1)
%% Zeroin algorithm
% Dekker's algorithm keeps three variables, $a$, $b$, and $c$:
% Initially, $c$ is set equal to $a$.
%
% * $b$ is the best zero so far, in the sense that $f(b)$ is the smallest
% value of $f(x)$ so far.
% * $a$ is the previous value of $b$, so $a$ and $b$ produce the secant.
% * $c$ and $b$ bracket the sign change, so $b$ and $c$ provide the midpoint.
%%
% At each iteration, the choice is made from three possible steps:
%
% * a minimal step if the secant step is within roundoff error of an interval
% endpoint.
% * a secant step if that step is within the interval and not within
% roundoff error of an endpoint.
% * a bisection step otherwise.
%% Zeroin in MATLAB
type zeroin
%%
% And here is the performance on our test function.
zeroin(f,3,4)
%%
% The minimal step even helps get things away from the pole.
% A few bisection steps get the interval down to
%
% $$ [3 \frac{1}{8}, 3 \frac{1}{4}] $$
%
% Then secant can safely take over and obtain a zero in half a dozen steps.
The test function
f = @(x) 1./(x-3)-6;
ezplot(f,[3,4])
hold on
plot(3+1/6,0,'ro')
set(gca,'xtick',[3:1/6:4])
hold off
This function is intentionally tricky. There is a pole at x=3 and the zero we are trying to find is nearby at x=316. The only portion of the real line where the function is positive is on the left hand one-sixth of the above x-axis between these two points.
II. Muller’s Method
Muller’s method is a generalization of the secant method, in the sense that it does not require the derivative of the function. Muller's method find a root of the equation
\( f(x) =0 . \) It is an iterative method that requires three starting points
\( \left( p_0 , f(p_0 ) \right) , \ \left( p_1 , f(p_1 ) \right) , \ \left( p_2 , f(p_2 ) \right) . \) A parabola is constructed that passes through the three points; then the quadratic formula is used to find a root of the quadratic for the next approximation. It has been proved that near a simple root Muller’s method converges faster than the secant method and almost as fast as Newton’s method. The method can be used to find real or complex zeros of a function and can be programmed to use complex arithmetic.
Without loss of generality, we assume that p2 is the best approximation to the root and consider the parabola through the three starting values. Make the change of variable
\[
t= x- p_2 ,
\]
and use the differences
\[
h_0 = p_0 - p_2 , \qquad h_1 = p_1 - p_2 .
\]
Consider the quadratic polynomial involving the variable
t:
\[
y = at^2 +bt +c
\]
that passes through these three initial points:
\begin{align*}
\mbox{at } t&= h_0: \qquad ah_0^2 +bh_0 +c = f_0 = f(h_0 ) , \\
\mbox{at } t&= h_1: \qquad ah_1^2 +bh_1 +c = f_1 = f(h_1 ) , \\
\mbox{at } t&= 0: \qquad a0^2 +b0 +c = f_2 = f(0 ) , \\
\end{align*}
Solving these three equations, we find
\[
a= \frac{\left( f_0 -c \right) h_1 - \left( f_1 -c \right) h_0}{h_1 h_0^2 - h_1^2 h_0} , \qquad b = \frac{\left( f_1 -c \right) h_0^2 - \left( f_0 -c \right) h_1^2}{h_1 h_0^2 - h_1^2 h_0} , \qquad c= f_2 .
\]
The quadratic formula is used to find the roots
\( t = z_1 , \ z_2 \) of the equation
\( at^2 + bt +c =0 : \)
\[
z = \frac{-2c}{b \pm \sqrt{b^2 - 4ac}} .
\]
To update the iterates, throw out the one of the initial points that is farthest away. Although a lot of auxiliary calculations are done in Muller’s method, it only requires one function evaluation per iteration.
If Muller’s method is used to find the real roots of \( f(x) =0 , \) it is possible that one may encounter complex approximations, because the roots of the quadratic in \( at^2 + bt +c =0 \) might b ecomplex (nonzero imaginary components). In these cases the imaginary components will have a small magnitude and can be set equal to zero so that the calculations proceed with real numbers.
function [p, y, err] = muller(f,p0,p1,p2,delta,epsilon,max1)
% Input: f is the object function input as a sring 'f'
% p0, p1, and p2 are the initial approximations to a zero
% delta is the tolerance for p0, p1, and p2
% epsilon is the tolerance for the function values y
% max1 is the maximum number of iterations
% Output: p is the Muller approximation to the zero/null of f
% err is the error in the approximation of p
% y is the function value y = f(p)
% initialize the matrices P and Y
P=[p0 p1 p2];
Y=feval(f,P);
% calculate a and b
for k=1:max1
h0=P(1)-P(3); h1=P(2)-P(3); e0=Y(1)-Y(3); e1=Y(2)-Y(3); c=Y(3);
denom=h1*h0^2 - h0*h1^2;
a=(e0*h1-e1*h0)/denom;
b=(e1*h0^2 -e0*h1^2)/denom;
% suppress any complex roots
if b^2-4*a*c > 0
disc=sqrt(b^2-4*a*c);
else
disc=0;
end
% find the smallest root
if b < 0
disc=-disc;
end
z=-2*c/(b+disc);
p=P(3)+z;
% sort the entries of P to find the two closest to p
if abs(p-P(2)) < abs(p-P(1))
Q=[P(2) P(1) P(3)];
P=Q;
Y=feval(f,P);
end
if abs(p-P(3)) <: abs(p-P(2))
R=[P(1) P(3) P(2)];
P=R;
Y=feval(f,P);
end
% replace the entry of P that was farthest from p with p
P(3)=p;
Y(3)=feval(f,P(3));
y=Y(3);
% determine stopping criteria
err=abs(z);
relerr=err/(abs(p)+delta);
if (err <: delta)|(relerr < delta)|(abs(y) < epsilon)
break
end
end