Chapter 9
Loops and Logic
To use Matlab to solve many physics problems you have to
know how to write loops and
how to use logic.
9.1 Loops
A loop is a way of repeatedly executing a section of code. It is so
important to know how
to write them that several common examples of how they are used will be given
here. The
two kinds of loops we will use are the for loop and the while loop. We will look
at for
loops first, then study while loops a bit later in the logic section .
The for loop looks like this:
for n=1:N . . . end
which tells Matlab to start n at 1, then increment it by 1
over and over until it counts up
to N, executing the code between for and end for each new value of n . Here are a
few
examples of how the for loop can be used.
Summing a series with a for loop
Let's do the sum
with N chosen to be a large number
Example 9.1a (ch9ex1a.m)
% Example 9.1a (Physics 330)
s=0, % set a variable to zero so that 1/n^2 can
be repeatedly added to it
N=10000, % set the upper limit of the sum
for n=1:N % start of the loop
% add 1/n^2 to s each time, then put the answer
back into s
.
.
.
end % end of the loop
fprintf(' Sum = %g \n',s) % print the answer |
You may notice that summing with a loop takes a lot longer
than the matrix operator
way of doing it:
% calculate the sum of the squares of the reciprocals
of the
% integers from 1 to 10,000
n=1:10000,
sum(1./n.^2)
Try both the loop way in Example 9.1a and this sum command
way and see which is faster.
To slow things down enough that you can see the difference change 10,000 to
100,000.
(When we tested this, the : way was 21 times faster than the loop, so use array
operators
whenever you can.) To do timing checks use the tic and toc commands. Look them
up
in online help.
To get some more practice with loops, let's do the running
sum
for values of m from 1 to a large number N.
Example 9.1b (ch9ex1b.m)
% Example 9.1b (Physics 330)
clear,
close all,
N=100,
a = zeros(1,N),
% Fill the a array
for n=1:N
a(n) = 1 / n^2,
end
S = zeros(1,N),
% Do the running sum
for m=1:N
S(m) = sum( a(1:m) ),
end
% Now let's plot S vs . m
m=1:N
plot(m,S) |
Notice that in this example we pre -allocate the arrays a
and S with the zeros command
before each loop. If you don't do this, Matlab has to go grab an extra little
chunk of memory
to expand the arrays each time the loop iterates and this makes the loops run
very slowly
as N gets big.
We also could have done this cumulative sum using colon
operators and the cumsum
command, like this:
n=1:100,
S=cumsum(1./n.^2),
(but we are practicing loops here).
Products with a for loop
Let's calculate N! = 1 · 2 · 3
…(N - 1) · N using a for loop that starts at n = 1 and
ends
at n = N, doing the proper multiply at each step of the way .
Example 9.1c (ch9ex1c.m)
% Example 9.1c (Physics 330)
P=1, % set the first term in the product
N=20, % set the upper limit of the product
for n=2:N % start the loop at n=2 because we
already loaded n=1
P=P*n, % multiply by n each time and put the answer back into P
end % end of the loop
fprintf(' N! = %g \n',P) % print the answer |
Now use Matlab's factorial command to check that you found
the right answer:
factorial(20)
You should be aware that the factorial command is a bit
limited in that it won't act on
an array of numbers in the way that cos, sin, exp etc. do. A better factorial
command to
use is the gamma function -(x) which extends the factorial function to all
complex values .
It is related to the factorial function by -(N + 1) = N!, and is called in
Matlab using the
command gamma(x), so you could also check the answer to your factorial loop this
way:
gamma(21)
Recursion relations with for loops
Suppose that we were solving a differential equation by substituting into it
a power series
of the form
and that we had discovered that the coefficients a n satisfied the recursion
relation
To use these coefficients we need to load them into an array a so that a(1) =
a1, a(2) =
a2, . Here's how we could do this using a for loop to load a(1)…a(20):
Example 9.1d (ch9ex1d.m)
% Example 9.1d (Physics 330)
a(1)=1, % put the first element into the array
N=19, % the first one is loaded, so let's load 19 more
for n=1:N % start the loop
a(n+1)=(2*n-1)/(2*n+1)*a(n), % the recursion relation
end
disp(a) % display the resulting array of values |
Note that the recursion relation was translated into
Matlab code just as it appeared in the
formula: a(n+1)=(2*n-1)/(2*n+1)*a(n). The counting in the loop was then adjusted
to
t by starting at n = 1, which loaded a(1+1) = a(2), then a(3), etc., then ended
at n = 19,
which loads a(19 + 1) = a(20). Always make the code you write t the mathematics
as
closely as possible, then adjust the other coding to t. This will make your code
easier to
read and you will make fewer mistakes.
9.2 Logic
Often we only want to do something when some condition is satisfied, so we
need logic
commands. The simplest logic command is the if command, which works like this.
(Several
examples are given, try them all.)
Example 9.2a (ch9ex2a.m)
% Example 9.2a (Physics 330)
clear,
a=1,b=3,
% If the number a is positive set c to 1, if a
is 0 or negative,
% set c to zero
if a>0
c=1
else
c=0
end
% if either a or b is non-negative, add them to
obtain c,
% otherwise multiply a and b to obtain c
if a>=0 | b>=0 % either non-negative
c=a+b
else
c=a*b % otherwise multiply them to obtain c
end |
You can build any logical condition you want if you just
know the basic logic elements.
Here they are
Equal ==
Less than <
Greater than >
Less than or equal <=
Greater than or equal >=
Not equal ~=
And &
Or |
Not ~
There is also a useful logic command that controls loops:
while. Suppose you don't
know how many times you are going to have to loop to get a job done, but instead
want
to quit looping when some condition is met. For instance, suppose you want to
add the
reciprocals of squared integers until the term you just added is less than
1e-10. Then you
would change the loop in the example to look
like this
Example 9.2b (ch9ex2b.m)
% Example 9.2b (Physics 330)
clear
term=1 % load the first term in the sum, 1/1^2=1
s=term, % load s with this first term
% start of the loop - set a counter n to one
n=1,
while term > 1e-10 % loop until term drops
below 1e-10
n=n+1, % add 1 to n so that it will count: 2,3,4,5,...
term=1/n^2, % calculate the next term to add
s=s+term, % add 1/n^2 to s until the condition is met
end % end of the loop
fprintf(' Sum = %g \n',s) |
This loop will continue to execute until term<1e-10. Note
that unlike the for loop, here
you have to do your own counting, being careful about what value n starts at and
when
it is incremented (n = n + 1). It is also important to make sure that the
variable you are
testing (term in this case) is loaded before the loop starts with a value that
allows the test
to take place and for the loop to run (term must pass the while test.)
Sometimes while is awkward to use because you would rather
just loop lots of times
checking some condition and then break out of the loop when it is satisfied. The
break
command is designed to do this. When break is executed in a loop the script
jumps to just
after the end at the bottom of the loop. Here is our sum loop rewritten with
break
Example 9.2c (ch9ex2c.m)
% Example 9.2c (Physics 330)
clear
s=0, % initialize the sum variable
% start of the loop
for n=1:1000000
term=1/n^2,
% add 1/n^2 to s until the condition is met
s=s+term,
if term < 1e-10
break
end
% end of the loop
end
fprintf(' Sum = %g \n',s) |
9.3 Secant Method
Here is a real example that you will sometimes use to solve difficult
equations of the form
f(x) = 0 in Matlab. (Matlab's fzero command, which you will learn to use
shortly, does
this for you automatically, here you will see how they do it.)
The idea is to find two guesses x1 and x2 that are near a solution of this
equation.
(You find about where these two guesses ought to be by plotting the function and
seeing
about where the solution is. It's OK to choose them close to each other, like
x1 = .99
and x2 = .98.) Once you have these two guesses find the function values that go
with
them: f1 = f(x1) and f2 = f(x2) and compute the slope m =
(f2-f1)=(x2-x1) of the line
connecting the points. (You can follow what is happening here by looking at Fig.
9.1.) Then
t a straight line through these two points and solve the resulting straight line
equation
y - f2 = m(x - x2) for the value of x that makes y = 0, i.e., solve the line
equation to find
Figure 9.1 The sequence of approximate points in the secant
method.
as shown in Fig. 9.1. This will be a better approximation
to the solution than either of
your two initial guesses, but it still won't be perfect, so you have to do it
again using x2
and the new value of x3 as the two new points. This will give you x4 in the
figure. You can
draw your own line and see that the value of x5 obtained from the line between
(x3, f3) and
(x4, f4) is going to be pretty good. And then you do it again, and again, and
again, until
your approximate solution is good enough.
Here's what the code looks like that solves the equation
exp(-x) - x = 0
Example 9.3a (ch9ex3a.m)
% Exampmle 9.3a (Physics 330)
clear,close all,
%*********************************************************
% Define the function as an in line function (See Chapter 12
% for more details.)
%*********************************************************
func=inline('exp(-x)-x','x'),
% First plot the function
x=0:.01:2,
f=func(x),
plot(x,f,'r-',x,0*x,'b-')
%*********************************************************
% (Note that the second plot is just a blue x-axis (y=0)
% 0*x is just a quick way to load an array of zeros the
% same size as x)
52 Chapter 9 Loops and Logic
% From the plot it looks like the solution is near x=.6
% Secant method to solve the equation exp(-x)-x = 0
% Use an initial guess of x1=0.6
%*********************************************************
x1=0.6,
% find f(x1)
f1=func(x1),
% find a nearby second guess
x2=0.99*x1,
% set chk, the error, to 1 so it won't trigger
the while
% before the loop gets started
chk=1,
% start the loop
while chk>1e-8
% find f(x2)
f2=func(x2),
% find the new x from the straight line approximation and print it
xnew = x2 - f2*(x2-x1)/(f2-f1)
% find chk the error by seeing how closely f(x)=0 is approximated
chk=abs(f2),
% load the old x2 and f2 into x1 and f1, then put the new x into x2
x1=x2,f1=f2,x2=xnew,
% end of loop
end |
(Note: this is similar to Newton's method, also called
Newton-Raphson, but when
a finite-difference approximation to the derivative is used it is usually called
the secant
method.)
9.4 Using Matlab's Fzero
Matlab has its own zero- finder which probably is similar to the secant
method described
above. To use it you must make a special M- le called a function, which we will
discuss in
more detail in chapter 12. Here we will just give you a sample le so that you
can see how
fzero works. This function le (called fz.m here) evaluates the function f(x).
You just
need to build it, tell Matlab what its name is using the @-sign syntax
illustrated below, and
also give Matlab an initial guess for the value of x that satisfies f(x) = 0.
In the section of code below you will find the Matlab
function fz(x) and the line of code
invoking fzero that finds the root. The example illustrated here is f(x) =
exp(-x)-x = 0.
Here is the function M- le fz.m used by fzero in this
example: (Note: both of these
les must be stored in the same directory.)
Example 9.4a (fz.m)
% Example 9.4a (Physics 330)
function f=fz(x)
% evaluate the function fz(x) whose
% roots are being sought
f=exp(-x)-x,
|
Here is the Matlab code that uses fzero and fz to do the
solve:
Example 9.4b (ch9ex4b.m)
% Example 9.4b (Physics 330)
%*********************************************************
% Here is the matlab code that uses fz.m to find
% a zero of f(x)=0 near the guess x=.7
% Note that the @ sign is used to tell Matlab that
% the name of an M-file is being passed into fzero
%*********************************************************
x=fzero(@fz,.7) |