CHAPTER 11

Finding Errors and Testing Programs



11.1 Discussion
11.2 Diagnostic Messages
11.3 Using echo
11.4 The keyboard Command


11.1 Discussion


An effective way to debug long programs is to:

1) break the program into small parts and test each part separately,
2) list intermediate results in all calculations so they can be checked,
3) make use of the standard routines that do array operations so you reduce the number of looping operations,
4) test individual lines in a program in the Matlab Command window to make sure you understand the consequences of each,
5) learn what the error messages mean and where to look for their causes,
6) make use of any debugging tools that the system may provide.

So far we have spent most of our time on ways to follow the first four of these suggestions. This chapter will focus on the last two points.

Matlab is quite easy to debug since it is an interpretive language and you can test individual lines in it. In spite of this, complicated problems that involve a lot of looping operations may be hard to follow. Finding errors in such programs may take a lot longer than the original writing of the program.

11.2 Diagnostic Messages


The MATLAB User's Guide does not provide a comprehensive list of error messages. Diagnostics from individual operations (such as from matrix divide) are mentioned, but we could use something more complete. We will mainly be concerned with what you would find as a message when you try to execute one of your programs. Messages from direct executions in the command window are usually easy to interpret. First let's look at some of the errors that can arise in the use of a program that has been tested many times. These messages will all come from incorrect arguments given when the program was called. The programs ssec1 and ssec2 will be our test programs. Suppose we try:

>> ssec2(3,'sin(x)') 
 
Error in ==> /marsh/masc223/matlab/ssec1.m 
On line 13  ==> x=xs(2); 
Error in ==> /marsh/masc223/matlab/ssec2.m 
On line 24  ==>   x=ssec1(xs,fx,c); 

The error message is not a great help. Even if we list the program, it is not clear why we should have an error. If we think some, it could be that a) xs did not exist, or b) it did exist, but it did not have a second element. What about the possibility that it was a matrix? Would that have caused an error message? Try it:

>> xs=[1 2 
       3 4]; 
 
>> disp(xs(2)) 
       3 

Now, we can be pretty sure that it was one of the two listed reasons. How do we find which? You can in this case list the programs and find that xs was in the argument list for both ssec1 and ssec2. In fact it was the first argument and we just gave a scalar for it! Let's try a second stab at using ssec2:

>> ssec2([2 3],sin(x)) 
 
???  Undefined function or variable. 
Symbol in question ==> x 

Oh well that is easy to understand, we need to define x. We do so and try again:

>> x=2; 
 
>> ssec2([2 3],sin(x)) 
 
???  Index exceeds matrix dimensions. 
Error in ==> /marsh/masc223/matlab/ssec2.m 
On line 26  ==>   if (abs(xs(2)-xs(1))<=erc) 

That looks very confusing. We know we made xs, have two elements! What else could be wrong?

At this point we may be tempted to use some sort of trace if we are used to debugging in several other languages. One of our problems is that we do not know how we got to the point where the error occurred. The echo command in Matlab can help. If we use echo by itself, all commands in script files will be listed before they are executed. If we use echo funcnm, then the commands in the function called funcnm will be listed. Let's try that here.

>> echo ssec2 
 
>> ssec2([2 3],sin(x))  
 
???  Index exceeds matrix dimensions. 
Error in ==> /marsh/masc223/matlab/ssec2.m 
On line 26  ==>   if (abs(xs(2)-xs(1))<=erc) 

Well, that did not help. The error was found before any instructions were executed. Now we will have to rely on the help lines in the function to guide us:

>> help ssec2 
 
  function x=ssec2(xs,fx,c,erc,nmax) 
  xs gives an interval to seek a solution to f(x) = 0 in. 
  fx is a character vector that tells how to find f(x). 
  c is a vector of parameters in f(x) 
  erc gives the difference between successive values of x 
  allowed when convergence is deemed to be achieved. 
  nmax is the maximum number of trials, before quitting. 
  If erc and nmax are not given, then the program uses: 
     erc=.0001 and nmax=10 
  If only two arguments are given, c is set to null. 
  The program uses the function ssec1 for each iteration. 
  Example 1:>> cs=[1 -2 -4.25 7.5]; 
            >> disp(ssec2([2 3],'polyval(c,x)',cs,.0001,10)) 
  Example 2:>> disp(ssec2([3 4],'sin(x)')) 

If we compare the examples shown by the help command with what we tried, we can see that we left out the quotes around the function. Note that nearly all bugs are simple after you find them!

Here is one more case that is similar to the last one.

>> ssec2([2 3],'sin(x)',.001,10) 
 
???  Input argument is undefined. 
Symbol in question ==> nmax 
Error in ==> /marsh/masc223/matlab/ssec2.m 
On line 23  ==> for k=1:nmax 

This one is easy to understand, although it seems to be saying that we forgot to give it nmax, we can see that really we omitted the third argument. Matlab simply counts arguments, and when five are required it assumes the last one is the one you left out.


11.3 Using echo


The echo command looks like it would be very helpful, but our first try did not produce any results since the program did not execute at all. Here are a pair of very simple functions that will allow us to see what sort of information we could get from echo . The function tstecho1 calls tstecho2 ;n times:

It also passes two parameters to the function tstecho2. Here is tstecho2:

If we just execute the first function without echo on, we see:

>> tstecho1(2,3,-4) 
ans = 
   -0.9167 

Now let's turn echo on tstecho1 and try again:

>> echo tstecho1 on 
 
>> tstecho1(2,3,-4) 
 
function z=tstecho1(a,n,c) 
% function tstecho1(a,n,c) 
% Testing the echo function 
z=0; 
for k=1:n 
   z=z+tstecho2(a,c*k); 
end 
ans = 
   -0.9167 

We get a listing of each line of the program that is to be executed. Normally that is not too helpful. We could have gotten the same thing in an edit or shell window. Let's turn that echo off and echo the function that is called:

>> echo tstecho1 off 
 
>> echo tstecho2 on 
 
>> tstecho1(2,3,-4) 
 
function z=tstecho2(a,c) 
% function tstecho2(a,c) 
% Testing the echo function 
% Called by tstecho1 
z=a/c; 
 
function z=tstecho2(a,c) 
% function tstecho2(a,c) 
% Testing the echo function 
% Called by tstecho1 
z=a/c; 
 
function z=tstecho2(a,c) 
% function tstecho2(a,c) 
% Testing the echo function 
% Called by tstecho1 
z=a/c; 
 
ans = 
   -0.9167 

Now we see the listing for the function that is called, each time it is executed. We still do not get information about the arguments of the function when it is called however. That is usually the crucial information that can help us find ``bugs".


11.4 The keyboard Command


Now here is a command that sounds like it could be very helpful in debugging programs. Remember our problem in trying to decide which of two possibilities was causing ssec2 to bomb. We thought it was either because xs did not exist or it was not a vector. Here was the error message we were trying to interpret:

>> ssec2(3,'sin(x)') 
 
Error in ==> /marsh/masc223/matlab/ssec1.m 
On line 13  ==> x=xs(2); 
Error in ==> /marsh/masc223/matlab/ssec2.m 
On line 24  ==>   x=ssec1(xs,fx,c); 

Suppose we put in a keyboard command right before line 13 in ssec1:

fs1=eval(fx); 
keyboard 
x=xs(2); 

Then when we execute ssec2 , we get:

>> clear 
 
>> ssec2(3,'sin(x)',[],.001,10) 
 
K>> xs 
xs = 
     3 
 
K>>Error in ==> /marsh/masc223/matlab/ssec1.m 
On line 14  ==> x=xs(2); 
Error in ==> /marsh/masc223/matlab/ssec2.m 
On line 24  ==>   x=ssec1(xs,fx,c); 

Note the ``K" before the double prompt when the keyboard command is in effect. When we stop in the program, we can then list any variables such as xs to see what values they have assumed at that point in the calculation. The first time the program stopped, we typed xs to see what had happened to that variable. The second time it stopped, we typed, in lower case, the letters R-E-T-U-R-N and then pressed the RETURN key to signal the end of the list that we wanted to examine \. This may be crucial when you are trying to figure out what went wrong in a subroutine that is four deep in a complicated set of functions.


Continue on to Chapter 12 
Return to Table of Contents