Previous Up Next

Buy this book at Amazon.com

This HTML version of the book is provided as a convenience, but some math equations are not translated correctly. The PDF version is more reliable.

Chapter 3  Scripts

3.1  M-files

So far we have typed all of our programs “at the prompt,” which is fine if you are not writing more than a few lines. Beyond that, you will want to store your program in a script and then execute the script.

A script is a file that contains MATLAB code. These files are also called “M-files” because they use the extension .m, which is short for MATLAB.

You can create and edit scripts with any text editor or word processor, but the simplest way is by selecting NewScript from the File menu. A window appears running a text editor specially designed for MATLAB.

Type the following code in the editor

x = 5

and then press the (outdated) floppy disk icon, or select Save from the File menu. Either way, a dialog box appears where you can choose the file name and the directory where it should go. Change the name to myscript.m and leave the directory unchanged.

By default, MATLAB will store your script in a directory that is on the search path, which is the list of directories MATLAB searches for scripts.

Go back to the Command Window and type myscript (without the extension) at the prompt. MATLAB executes your script and displays the result.

>> myscript
x = 5

When you run a script, MATLAB executes the commands in the M-File, one after another, exactly as if you had typed them at the prompt.

If something goes wrong and MATLAB can’t find your script, you will get an error message like:

>> myscript
Undefined function or variable 'myscript'.

In this case you can either save your script again in a directory that is on the search path, or modify the search path to include the directory where you keep your scripts. You’ll have to consult the documentation for the details (sorry!).

The filename can be anything you want, but you should try to choose something meaningful and memorable. You should be very careful to choose a name that is not already in use; if you do, you might accidentally replace one of MATLAB’s functions with your own. Finally, the name of the file cannot contain spaces. If you create a file named my script.m, MATLAB will complain when you try to run it:

>> my script
Undefined function or variable 'my'.

The problem is that it is looking for a script named my. The problem is even worse if the first word of the filename is a function that exists. Just for fun, create a script named abs val.m and run it.

Keeping track of your scripts can be a pain. To keep things simple, for now, I suggest putting all of your scripts in one directory of your own.

Exercise 1   The Fibonacci sequence, denoted F, is described by the equations F1 = 1, F2 = 1, and for i ≥ 3, Fi = Fi−1 + Fi−2. The elements of this sequence occur naturally in many plants, particularly those with petals or scales arranged in the form of a logarithmic spiral.

The following expression computes the nth Fibonacci number:

Fn = 
1
5









1 + 
5
2
 


n



 
 −


1 − 
5
2
 


n



 






    (1)

Translate this expression into MATLAB and store your code in a file named fibonacci1.m. At the prompt, set the value of n to 10 and then run your script. The last line of your script should assign the value of Fn to ans. Try outputting ans with both format short and format long. Notice, especially with the long format, that the answer is not exactly 55 as it should be for F10. This is due to things like rounding errors as the expression was being calculated.

3.2  Why scripts?

The most common reasons to use scripts are:

  • When you are writing more than a couple of lines of code, it might take a few tries to get everything right. Putting your code in a script makes it easier to edit than typing it at the prompt.

    On the other hand, it can be a pain to switch back and forth between the Command Window and the Editor. Try to arrange your windows so you can see the Editor and the Command Window at the same time, and use the Tab key or the mouse to switch between them.

  • If you choose good names for your scripts, you will be able to remember which script does what, and you might be able to reuse a script from one project to the next.
  • If you run a script repeatedly, it is faster to type the name of the script than to retype the code!

Unfortunately, the great power of scripts comes with great responsibility, which is that you have to make sure that the code you are running is the code you think you are running.

First, whenever you edit your script, you have to save it before you run it. If you forget to save it, you will be running the old version.

Also, whenever you start a new script, start with something simple, like x=5, that produces a visible effect. Then run your script and confirm that you get what you expect. MATLAB comes with a lot of predefined functions. It is easy to write a script that has the same name as a MATLAB function, and if you are not careful, you might find yourself running the MATLAB function instead of your script.

Either way, if the code you are running is not the code you are looking at, you will find debugging a frustrating exercise! And that brings us to the Third Theorem of Debugging:

You must always be 100% sure that the code you are running is the code you think you are running.

3.3  The workspace

The variables you create are stored in the workspace, which is a set of variables and their values. The clear command, by itself, removes any variables you may have in the workspace.

>> clear

The who command prints the names of the variables in the workspace.

>> x=5;
>> y=7;
>> z=9;
>> who

Your variables are:

x  y  z

The clear command can also remove specified variables.

>> clear x y
>> who

Your variables are:

z

To display the value of a variable, you can use the disp function.

>> disp(z)
     9

But it’s easier to just type the variable name.

>> z
z = 9

3.4  More errors

Again, when you try something new, you should make a few mistakes on purpose so you’ll recognize them later.

The most common error with scripts is to run a script without creating the necessary variables. For example, fibonacci1 requires you to assign a value to n. If you don’t:

>> fibonacci1
Undefined function or variable 'n'.

Error in fibonacci1 (line 9)
diff = t1^n - t2^n;

The details of this message might be different for you, depending on what’s in your script. But the general idea is that n is undefined. Notice that MATLAB tells you what line of your program the error is in, and displays the line.

This information can be helpful, but beware! MATLAB is telling you where the error was discovered, not where the error is. In this case, the error is not in the script at all; it is, in a sense, in the workspace.

Which brings us to the Fourth Theorem of Debugging:

Error messages tell you where the problem was discovered, not where it was caused.

The object of the game is to find the cause and fix it—not just to make the error message go away.

3.5  Pre- and post-conditions

Every script should contain a comment that explains what it does, and what the requirements are for the workspace. For example, I might put something like this at the beginning of fibonacci1:

% Computes the nth Fibonacci number.
% Precondition: you must assign a value to n before running
% this script.  Postcondition: the result is stored in ans.

A precondition is something that must be true, when the script starts, in order for it to work correctly. A postcondition is something that will be true when the script completes.

If there is a comment at the beginning of a script, MATLAB assumes it is the documentation for the script, so if you type help fibonacci1, you get the contents of the comment (without the percent signs).

>> help fibonacci1
  Computes the nth Fibonacci number.
  Precondition: you must assign a value to n before running
  this script.  Postcondition: the result is stored in ans.

That way, scripts that you write behave just like predefined scripts. You can even use the doc command to see your comment in the Help Window.

3.6  Assignment and equality

In mathematics the equals sign means that the two sides of the equation have the same value. In MATLAB an assignment statement looks like a mathematical equality, but it’s not.

One difference is that the sides of an assignment statement are not interchangeable. The right side can be any legal expression, but the left side has to be a variable, which is called the target of the assignment. So this is legal:

>> y = 1;
>> x = y+1
x = 2

But this is not:

>> y+1 = x
 y+1 = x
     |
Error: The expression to the left of the equals sign is not a
valid target for an assignment.

In this case the error message is pretty helpful, as long as you know what a “target” is.

Another difference is that an assignment statement is only temporary, in the following sense. When you assign x = y+1, you get the current value of y. If y changes later, x does not get updated.

A third difference is that a mathematical equality is a statement that may or may not be true. For example, y = y+1 is a statement that happens to be false for all values of y. In MATLAB, y = y+1 is a sensible and useful assignment statement. It reads the current value of y, adds one, and replaces the old value with the new value.

>> y = 1;
>> y = y+1
y = 2

When you read MATLAB code, you might find it helpful to pronounce the equals sign “gets” rather than “equals.” So x = y+1 is pronounced “x gets the value of y plus one.”

To test your understanding of assignment statements, try this exercise:

Exercise 2   Write a few lines of code that swap the values of x and y. Put your code in a script called swap and test it.

3.7  Incremental development

When you start writing scripts that are more than a few lines, you might find yourself spending more and more time debugging. The more code you write before you start debugging, the harder it is to find the problem.

Incremental development is a way of programming that tries to minimize the pain of debugging. The fundamental steps are

  1. Always start with a working program. If you have an example from a book or a program you wrote that is similar to what you are working on, start with that. Otherwise, start with something you know is correct, like x=5. Run the program and confirm that you are running the program you think you are running.

    This step is important, because in most environments there are lots of little things that can trip you up when you start a new project. Get them out of the way so you can focus on programming.

  2. Make one small, testable change at a time. A “testable” change is one that displays something on the screen (or has some other effect) that you can check. Ideally, you should know what the correct answer is, or be able to check it by performing another computation.
  3. Run the program and see if the change worked. If so, go back to Step 2. If not, you will have to do some debugging, but if the change you made was small, it shouldn’t take long to find the problem.

When this process works, you will find that your changes usually work the first time, or the problem is obvious. That’s a good thing, and it brings us to the Fifth Theorem of Debugging:

The best kind of debugging is the kind you don’t have to do.

In practice, there are two problems with incremental development:

  • Sometimes you have to write extra code to generate visible output that you can check. This extra code is called scaffolding because you use it to build the program and then remove it when you are done. But time you save on debugging is almost always worth the time you spend on scaffolding.
  • When you are getting started, it is usually not obvious how to choose the steps that get from x=5 to the program you are trying to write. There is an extended example in Section 6.7.

If you find yourself writing more than a few lines of code before you start testing, and you are spending a lot of time debugging, you should try incremental development.

3.8  Unit testing

In large software projects, unit testing is the process of testing software components in isolation before putting them together.

The programs we have seen so far are not big enough to need unit testing, but the same principle applies when you are working with a new function or a new language feature for the first time. You should test it in isolation before you put it into your program.

For example, suppose you know that x is the sine of some angle and you want to find the angle. You find the MATLAB function asin, and you are pretty sure it computes the inverse sine function. Pretty sure is not good enough; you want to be very sure.

Since we know sin0 = 0, we could try

>> asin(0)
ans = 0

which is correct. Also, we know that the sine of 90 degrees is 1, so if we try asin(1), we expect the answer to be 90, right?

>> asin(1)
ans = 1.5708

Oops. We forgot that the trig functions in MATLAB work in radians, not degrees. So the correct answer is π/2, which we can confirm by dividing through by pi:

>> asin(1) / pi
ans = 0.5000

With this kind of unit testing, you are not really checking for errors in MATLAB, you are checking your understanding. If you make an error because you are confused about how MATLAB works, it might take a long time to find, because when you look at the code, it looks right.

Which brings us to the Sixth Theorem of Debugging:

The worst bugs aren’t in your code; they are in your head.

3.9  Glossary

M-file:
A file that contains a MATLAB program.
script:
An M-file that contains a sequence of MATLAB commands.
search path:
The list of directories where MATLAB looks for M-files.
workspace:
A set of variables and their values.
precondition:
Something that must be true when the script starts, in order for it to work correctly.
postcondition:
Something that will be true when the script completes.
target:
The variable on the left side of an assignment statement.
incremental development:
A way of programming by making a series of small, testable changes.
scaffolding:
Code you write to help you program or debug, but which is not part of the finished program.
unit testing:
A process of testing software by testing each component in isolation.

3.10  Exercises

Exercise 3  

Imagine that you are the owner of a car rental company with two locations, Albany, and Boston. Some of your customers do “one-way rentals,” picking up a car in Albany and returning it in Boston, or the other way around. Over time, you have observed that each week 5% of the cars in Albany are dropped off in Boston, and 3% of the cars in Boston get dropped off in Albany. At the beginning of the year, there are 150 cars at each location.

Write a script called car_update that updates the number of cars in each location from one week to the next. The precondition is that the variables a and b contain the number of cars in each location at the beginning of the week. The postcondition is that a and b have been modified to reflect the number of cars that moved.

To test your program, initialize a and b at the prompt and then execute the script. The script should display the updated values of a and b, but not any intermediate variables.

Note: cars are countable things, so a and b should always be integer values. You might want to use the round function to compute the number of cars that move during each week.

If you execute your script repeatedly, you can simulate the passage of time from week to week. What do you think will happen to the number of cars? Will all the cars end up in one place? Will the number of cars reach an equilibrium, or will it oscillate from week to week?

In the next chapter we will see how to execute your script automatically, and how to plot the values of a and b versus time.

Are you using one of our books in a class?

We'd like to know about it. Please consider filling out this short survey.


Think Bayes

Think Python 2e

Think Stats 2e

Think Complexity


Previous Up Next