This lab will go more smoothly if you have read certain sections of the Chapter called "Logical Functions and Control Structures" in your "MATLAB by Holly Moore" textbook.
This is probably Chapter 8 in most of your books.
Sections of that chapter you should read before doing this lab, if possible:
This week, in lab05, we will give you some practice with control structures (chapter 8 in the MHM textbook):
In the process, we'll talk about how to refactor some of our test code to make it easier to work with.
We'll learn about a few MATLAB functions:
We'll learn about concatenating character strings by constructing new matrices with
By the time you complete this lab, you should be able to:
mod(x,m)function will be for simple values of x and m
fprintfwill be for certain simple cases (as illustrated later in this lab.)
By now we assume you are entirely familiar with these items, and will no longer describe them in detail:
To prepare for this week's lab, do all the following steps. If you are not sure what to do at any stage, you can consult earlier labs for details:
/www/htdocs/CIS/105/haggerty/07F/labs/lab05into your new directory
/www/htdocs/CIS/105/haggerty/07F/labs/lab05ainto your new directory
Because there are lots of files this week, we are dividing them into two directories:
In this step, you'll learn a bit about two useful MATLAB functions that print output, namely:
You'll also learn about working with MATLAB variables that store text. In MATLAB these variables are called character arrays. They are also sometimes called strings.
You could easily skip this step, and your instructor or TA would never know. Until, that is, you
Then, we'll know. So, don't skip this step.
fprintf, part 1—the newline thingy
fprintf can be used to print out stuff. Try these commands at the MATLAB prompt:
>> disp('hello'); hello >> fprintf('hello'); hello>>
Notice how the MATLAB prompt
>> comes immediately after the second
Right away, we see one difference between
disp prints its output and moves to a new line, but
If we want a new line after hello with
fprintf, we need to put
\n at the end of our string:
>> fprintf('hello\n'); hello >>
If we put a \n at the end of a character string with disp, what will happen? You might expect that we would get an extra new line, but that is not what happens:
>> disp('hello\n'); hello\n >>
\n is only interpreted as a new line character when it is used with
fprintf. Indeed, if we include \n in a character array, it is interpreted as two separate characters. Notice the size is
>> x='\n' x = \n >> whos x Name Size Bytes Class Attributes x 1x2 4 char >>
(We'll see later that in C++, this is not the case—In C++, as in Java and many other languages,
\n is always interpreted as a single character, namely the newline character.)
fprintf, part 2 —printing variables
disp, if you put something in quotes, it prints out the value literally. If you don't put that thing in quotes, it interprets it as the name of a variable, and tries to print the value. For example, notice the difference between
>> x = 5; >> disp('x'); x >> disp(x); 5 >>
If we try this with
fprintf, we get different results:
>> x = 7; >> fprintf('x'); x>> fprintf(x); ??? Error using ==> fprintf No format string. >>
In the first case,
x just like we expected—and without going to a new line before the MATLAB prompt
>>, just as we expected. But in the second case,
fprintf(x), we get an error:
No format string. What is the reason?
The reason is this: fprintf must always have a string as its first argument.
For example, suppose we write an assignment statement to give a value to
x. We can then use
fprintf to print the string
x= followed by the value of
x, and then go to a new line, like this:
>> x = 3 + 4;
The %f stands in place of where the variable x will be printed, and the \n stands in place of where the new line character will go.
There are many other options for the format string, and it is also possible to print multiple variables in a single format string. Read more about format strings in your "Matlab, by Holly Moore" textbook: Chapter 7, section 2, "Output Options".
You can also type
help fprintf and/or
help disp at the MATLAB prompt to learn more, as well as doing web searches on "MATLAB fprintf" and "MATLAB disp".
Another important concept is the concept of combining character strings.
Suppose we assign values as follows:
>> fname = 'Fred'; >> lname = 'Flintstone';
Then we can combine the two names into one by combining them inside a set of [ ]. This takes the the character arrays and sticks them together:
>> fullName = [fname lname] fullName = FredFlintstone >>
We sometimes call this operation string concatenation—this is a fancy computer science way of saying "stick 'em together".
Notice that the full name ended up without a space between Fred and Flintstone. We can fix this by including a space when we do the concatenation operation:
>> fullName = [fname ' ' lname] fullName = Fred Flintstone >>
We'll use this string concatenation trick inside one of the function M-files later in this lab.
The if/else statement is covered in chapter 8 of your MATLAB, by Holly Moore textbook, in Section 4, "Selection Structure". It would be helpful to review that section prior to doing this step in the lab.
We've already seen the if/else statement in the test scripts from lab02 and lab03. Take a look at each of these, and remind yourself of the places you've already seen the if/else, and how it works.
The if/else is also useful in writing certain function M-files. For example, we can write a function M-file that tests whether a number is odd or even. Look at the function M-file
isOdd.m that you copied into your
lab05a directory in Step 1.
Move into your ~/cisc105/lab05a directory, and try typing each of the following at the MATLAB prompt. Notice that in each case, the answer
1 indicates true, while the answer
0 indicates false.
isOdd() function uses the built-in MATLAB function
mod(), which computes the remainder after integer division, to determine whether a number is odd or even. Before we go further, we need to understand this
mod(x,2)means "divide the number x by 2. If two is evenly divisible by 2, then return 0, but if x is not evenly divisible by 2, return the remainder."
mod(27,3)at the MATLAB prompt. Notice that MATLAB returns 0 because Then try:
modmay appear on one of the exams.
There are various approaches to using the mod function with negative numbers, as this web page explains:
For purposes of CISC105 quizzes/exams, unless the issue arises in some later programming assignment, I don't plan to ask quiz/exam questions about mod involving negatives—I just want you to be aware of the issue. (Thanks to TA Colin Kern for pointing out the issue, and calling my attention to this web page.)
On a related issue, MATLAB actually has two functions for calculating mod. According to the MATLAB reference for the mod function:
mod(X,Y) and rem(X,Y) are equal if X and Y have the
same sign, but differ by Y if X and Y have different signs.
(Thanks to Prof. Terry Harvey for pointing this out.)
Among the files you copied for this week's lab into
~/cisc105/lab05a are two testing scripts for the isOdd function:
Look first at the script
testIsOdd.m. You'll see that this script looks very much like all the testing scripts we've seen before. There is one exception: since we are dealing only with the values
true, we can directly test
if (actual == expected). There is no need to use a
tolerance value and test the difference between the
expected values, as we did in earlier scripts.
Next, run the testIsOdd.m script, as shown here:
>> testIsOdd test 1 passed test 2 passed test 3 passed test 4 passed >>
You can see that all four tests pass. Now try running the alternative test script, test2IsOdd.m:
>> test2IsOdd test 1 passed test 2 passed test 3 passed test 4 passed test 5 passed >>
test2IsOdd.m has five tests rather than four, you might expect it to be a longer script. But look inside, and there is a surprise—
test2IsOdd is actually a much shorter script.
We can measure how much shorter by using the Unix command
wc -l filename, which tells us how many lines are in a file.
wc -lis a lowercase letter
las in lines, not the number
1as in the integer between 0 and 2.
> wc -l testIsOdd.m 84 testIsOdd.m > wc -l test2IsOdd.m 13 test2IsOdd.m >
This output tells us that testIsOdd.m contains 84 lines, while test2IsOdd.m contains only 13. How is it that
test2IsOdd.m gets more work done with 84.5% less code (of course, I computed this using MATLAB...)
>> (84 - 13)/84 ans =
Look inside the file
test2IsOdd.m and you can find the answer—there is another function M-file involved.
Locate this other helper function, and look inside and try to understand how this works.
Inside this helper file, notice especially the line of code:
disp(['test ' testNum ' passed']);
Do you see how this uses the skills we learned in step 2?
Once you've understood how the
test2IsOdd.m file and its companion function M-file, you can now tackle the next step.
Now move into your
~/cisc105/lab05 directory. We are going to do some work that is part of what you will turn in for credit.
Back in lab03, you worked produced a function M-file called
distance.m to compute the distance function. In lab03, a test file called
testDistance.m was supplied for you.
This week's lab also contains a version of
testDistance.m, but it is different. Use the links below to compare the two files:
The new version of
testDistance.m uses a function M-file to partially automate the repeated testing—similar to the way that
test2IsOdd.m did —but in this case I have not supplied you with that function M-file. Your job is to supply the missing file.
First, copy your
distance.m function M-file from your
~/cisc105/lab03 directory into your
~/cisc105/lab05 directory. (By now, you should know the Unix command to do that—this represents a potential exam question!)
Then, look over the
testDistance.m file from this week's lab. Notice the lines such as these:
performDiffTest( distance(1,5,-2,1), 5, 0.001, '1'); performDiffTest( distance(-2,-3,-4,4), 7.28, 0.001, '2');To supply an M-file that makes these lines possible, the first line of the function M-file you need to write should be as follows:
function result = performDiffTest(actual,expected,tolerance,testNum)
This first line is sometimes called the contract, and is also sometimes called the function prototype. From this function prototype, you can determine the name of the file you will need.
Write this file, and then test it by running the testDistance script at the MATLAB prompt. You should get the following output:
>> testDistance test 1 passed test 2 passed >>
When you get this, you are finished with step 3. You'll document this step later as part of a diary file for this lab.
This would be a good time to make sure your understanding of the
if/elseif/else statements is solid.
Among the files you copied into the
~/cisc105/lab05a directory are six simple scripts that use the
if/elseif/else statements, named
ifElse2.m, etc. through
Fair Warning: An upcoming "pop-quiz" may feature questions similar to those represented by these
if/else/elseif files, so don't skip this step even though there is nothing you have to turn in for grading.
They are not "practical" examples of how to use if/else to solve real world problems. The only purpose of these scripts is to test your understanding of how if/else and if/elseif/else statements work. These scripts are like "kickboard practice" in swimming, or "playing scales" on a musical instrument.
First, change directory to your
~/cisc105/lab05a directory, and locate these scripts.
For each script:
If you want some example of "practical" uses of the if/else and if/elseif/else, read you can find some in the textbook MATLAB, by Holly Moore text, in the chapter titled Logical Functions and Control Structures (probably Chapter 8)—see section 4 of that chapter.
Just as in Step 5, we practiced with the if/else, we can also practice with the while loop, another control structure discussed in Chapter 8 of MATLAB by Holly Moore.
The instructions for Step 5 are the same as for Step 4, except that this time we are working with the files
while2.m, etc. through
while6.m. These files are also in the
~/cisc105/lab05a directory, and can be found at the web link
The caution about a pop quiz applies equally here. So don't skip this step even though there is nothing you have to turn in for grading.
You guessed it—now we practice with for loops in the same manner, using the files
for6.m. These files are also in the
~/cisc105/lab05a directory, and can be found at the web link
Be sure your skills with for loops are solid before proceeding, because—you guessed it—there could be a quiz.
There's nothing to turn in for this step—but later steps in this lab that do require you to turn in something depend on work you do in this step.
forloop in a function M-file:
We can use a for loop inside a function M-file to print out a line made up of a certain character. For example, see the function M-file lineOfx.m:
function result = lineOfx(howMany) %lineOfx return a string made up of the letter x (howMany times) % % consumes: howMany, a scalar number indicating how many times % the letter x should appear % produces: a string made up of the letter x that many times % % if x <= 0, an empty string is returned % % Examples: % >> lineOfx(3) % ans = % xxx % >> lineOfx(5) % ans = % xxxxx % >> lineOfx(-10) % ans = % '' % >> % P. Conrad for CISC105, 10/07/2007 result = ''; for i=1:howMany result = [ result 'x' ]; end; return; end % function lineOfx
When we run this function at the MATLAB prompt, we get a line of x, just like in the examples:
>> lineOfx(-2) ans = '' >>
Note the last example there: the result is an empty matrix. This will end up being an interesting example, as we'll see later in Step 8.
We can get rid of all the excess spaces and the the
ans = business by making our function call to
boxOfx() be an argument to the
lineOfx()inside another function M-file:
We can use the
lineOfx() function inside another M-file called
boxOfx() to produce a box of x characters:
function result = boxOfx(width) %boxOfx return a square made up of the letter x % % consumes: width, a scalar number indicating how many times % the letter x should appear % produces: a square box made up of the letter x % % if x <= 0, an empty string is returned % % Examples: % >> boxOfx(3) % ans = % % xxx % xxx % xxx % % >> lineOfx(5) % ans = % % xxxxx % xxxxx % xxxxx % xxxxx % xxxxx % % >> lineOfx(-10) % ans = % '' % >> % P. Conrad for CISC105, 10/07/2007 result = ; % set result to the empty matrix for i=1:width result = [ result ; lineOfx(width) ]; %add a row end; return;
Here's sample output from that function:
>> disp(boxOfx(3)) xxx xxx xxx >> disp(boxOfx(4)) xxxx xxxx xxxx xxxx >> disp(boxOfx(2)) xx xx >> disp(boxOfx(-1)) >>
So, we might try making a test script for
boxOfx.m, but we run into some problems. Read on:
In the lab05 directory this week, there is a file called
testBoxOfx.m, which is a good start at a test script for
boxOfx.m. It works for the first two tests, but the third test fails. Your job is to fix this problem.
To find the problem, try running the test script. You should get output like the following:
>> testBoxOfx test 1 passed test 2 passed
test 3 failed
So, this is a bit confusing—expected and actual appear to be the same. We can type whos and see that indeed both are empty matrices:
>> clear >> whos >> testBoxOfx test 1 passed test 2 passed test 3 failed expected =  actual =  >> whos Name Size Bytes Class Attributes actual 0x0 0 double expected 0x0 0 double >>
So, why doesn't the test of
if (actual == expected) work? We'll look into this more in Step 8b.
MATLAB is a commercial software product, produced by a company called "The MathWorks". At the company's website http://www.mathworks.com, you can find lots of information about MATLAB.
In particular, there is a page about operations on the Empty Matrix that will shed light on the situation we are facing here. Here's a link to that page:
Read about the problems with testing the empty matrix for equality. Find the answer to this question:
Also read about the functions that operate on the empty matrix—in particular, the function:
Given that test 3 is checking to see whether the actual value is an empty matrix, we can replace the statement:
with some expression involving this
Your task in the next step: figure out what to replace this line of code with so that the test script works properly
Using the information you learned in Step 8b, modify the test script so that it works properly for testing the case of returning an empty matrix.
Now, write a test script for the function M-file
When I say "from scratch", I only mean that I'm not giving you a file to work from. However, you should feel free to start with the
testBoxOfx.m script as your starting point—you can use a Unix or a MATLAB command to copy from
testLineOfx.m, and then edit that file.
Once you are finished with both test scripts, you can proceed to the next step—we'll make a diary to show your work later in step 10 of this lab.
In this step, we'll put together a way of converting from decimal to binary using MATLAB.
dec2bin()that does this conversion—however, that's not the point.
dec2bin()function in MATLAB didn't come from nowhere, or from omniscient, omnipotent deity. Some poor human had to write the instructions—and someday, that person might be you.
So, in this exercise, you need to write a function M-file that converts decimal to binary, but does NOT use the built in dec2bin function. It will be a great way to practice with while loops, for loops and if/else, all at the same time
As you may remember, we can convert from decimal to binary by thinking in terms of "coins" that have denominations in powers of two.
For example, to convert 84 from decimal to binary, we first list the powers of two that we will need, starting with 1, and proceeding until have gone past 84:
We don't actually write down 128, because we realize that it is bigger than 84. Also, we actually need the build the list so that the powers of two go from largest to smallest:
One way to express this is with a while loop:
start with an empty list of powers of two
start with the power 1 while (the power is less than the number) add this power to the list (at the very end)
multiply that power by two
When we write a mixture of english sentences and control structures (things like if/else, while, and for loops), we call is pseudocode. Pseudocode is a helpful tool in writing software.
Of course, to actually convert we then need to process these powers from largest to smallest, subtracting the ones that are smaller than the number we are processing. Here's a list of the steps, as pseudocode:
howMuchLeft = 84 Is 64 <= 84? Yes! So subtract: howMuchLeft = howMuchLeft - 64 = 20, and write 1 Is 32 <= 20? No! so write 0 Is 16 <= 20? Yes! So subtract: howMuchLeft = howMuchLeft - 16 = 4, and write 1 Is 8 <= 4 No! so write 0 Is 4 <= 4 Yes! So subtract: howMuchLeft = howMuchLeft - 4 = 0, and write 1 Is 2 <= 0 No! so write 0 Is 1 <= 0 No! so write 0 And we have written: 1010100, which is indeed 84 in binary.
So, We can express this second part with a while loop also:
make a vector called powers with all the powers of two,
in descending order, from the one just bigger than the one
we want to convert, all the way down to 1
make a empty result vector howMuchLeft = the number we want to convert
for i = 1:length(powers) if (the ith element of powers <= howMuchLeft) subtract this power from howMuchLeft add the character '1' to end of the result vector else add the character '0' to end of the result vector end end
Given this pseudocode, we can write a MATLAB function M-file to solve the problem.
We'll do it in two parts. The first part, I will walk you through. For the second part, you are on your own to figure it out.
powersOf2Le(x)to test the test script
xis less than or equal to 0.
myDec2Bin(dec). For this step, you have the pseudocode above, plus the example of how to turn pseudocode into real code.
So, let's get on with it.
We'll start by writing the test script—writing the test first is always a good way to be sure that you know exactly what you want the script to do. This test script is in the files you copied in to your lab directory this week:
% testPowersOf2LeX.m test function powersOf2LeX(x) % P. Conrad for CISC105, sect 99, 10/07/2007 % Test function that produces a row vector of all powers of 2 <= x %%%%%%%%%%%%%%%%% % Run the tests % %%%%%%%%%%%%%%%%% % Test 1 actual = powersOf2LeX(80); expected = [64 32 16 8 4 2 1]; if (actual == expected) disp('test 1 passed'); else disp('test 1 failed'); expected actual end % Test 2 actual = powersOf2LeX(8); expected = [8 4 2 1]; if (actual == expected) disp('test 2 passed'); else % signal that test failed, and print both expected and actual disp('test 2 failed'); expected actual end % end testPowersOf2LeX.m
With this in place, we can proceed to writing the function M-file—first in stub form. The function M-file is not provided for you—you need to start it from scratch. From the test cases above, you should be able to deduce:
With that in place, add a stub for the body, like this one, so that we can "test the test script":
... result = ; return; end % end of function M-file
With the stub in place, we should get this result when running the test script:
>> testPowersOf2LeX test 1 failed expected = 64 32 16 8 4 2 1 actual = 42 test 2 failed expected = 8 4 2 1 actual = 42 >>
Now, we can replace the stub code (
result = ;) with some real code to calculate our result vector.
You need to work from the pseudocode to figure out the code yourself, but here are a few hints. These hints are all mixed up in terms of the order they come in in the code, though, to force you to think through the sequence of how things need to happen. You can use them to help you figure out how to convert the pseudocode into MATLAB code to calculate the result.
result = ;
result = [ x result ];
powerto 1, and multiply it by two each time through the while loop (
power = power * 2;)
power <= xis true.
When the test script passes, with a result like this you can move on to Step 9e.
>> testPowersOf2LeX test 1 passed test 2 passed >>
Now, add a third test case to
testPowersOf2LeX.m, one that tests for the case where you pass in a number less than or equal to zero. This should return the empty matrix, so you need to use the special way of testing for the empty matrix that we learned back in step 8c.
Run your test script again and you should get a result like this one:
>> testPowersOf2LeX test 1 passed test 2 passed test 3 passed >>
Now, with the powersOf2LeX(x) function working properly, you are ready to tackle the myDec2Bin(x) function. Start by writing a test script,
Next, write a stub for
myDec2Bin.m. Your stub should contain everything the goes in a function M-file—the first line, the comments with produces/consumes, examples, etc.—everything except the actual code to compute the result.
We will return the binary equivalent of the number x as a string, not as a number (since numbers in MATLAB are expressed in decimal). So, when you write your stub, use a string value as the "evil" value, e.g.
result = '42'; (42 obviously cannot be a legal binary value, since a legal binary value contains only zeros and ones.)
Try to get a result where the test fails, but where the test script runs with no MATLAB errors reported.
Then, write the body of myDec2Bin(x), following the pseudocode from step 9a. Some hints:
powersOf2LeX(x)function you wrote in step 9d to generate the vector of powers
forloop to step through the vector. The one in the pseudocode is pretty much what you need:
for i = 1:length(powers)—this is essentially already in MATLAB syntax.
vis expressed in MATLAB as
'x'to the end of a string variable
s, you can use:
s = [s 'x'];You'll use characters
'1'to build up your binary string.
The rest is up to you. Good luck, and have fun with it!
Now, we want to make a diary file called lab05.txt documenting the work from steps 3, 8 and 9 of this week's lab.
Put yourself inside MATLAB, inside the directory
~/cisc105/lab05, and start a diary file called
Then, do each of the following steps:
testDistance.mto show that the
performDiffTest.mfunction is working properly.
testBoxOfX.mto show that it works properly (including for the case of the empty matrix)
testLineOfX.mto show that it works properly (including for the case of the empty matrix
powersOf2LeX.mby typing in interactive function calls at the MATLAB prompt
myDec2Bin.mby typing in interactive function calls at the MATLAB prompt
Because for most of you, this is your first programming course, I have been spelling out in detail what steps you need to take to document your work. However, in subsequent weeks, there will be gradually fewer details in the instructions. You'll be expected to know that, in general, you need to:
What I hope you will begin to do is to
In this way, eventually you won't need me to tell you in such detail what you need to turn in. In fact, in second, third and fourth year programming courses, it is traditional that this is not spelled out in detail—students are, by that time, expected to understand what is needed. So, I want you to begin to acquire that skill, and as such, I'll be weaning you from the level of detail you may have come to expect.
Because we have several files this week to submit, we'll make things a bit easier for you and for the TA. Before uploading, we'll create a zip file that contains all of your files for this week.
Here's a list of all the files we want to put in the zip file for this week—all of these files (and only these files) should be in your lab05 directory.
Here's how to do it:
zip -r lab05 lab05 -i \*.m
You should get output like this:
> zip -r lab05 lab05 -i \*.m adding: lab05/testDistance.m (deflated 41%) adding: lab05/testBoxOfx.m (deflated 63%) adding: lab05/testPowersOf2LeX.m (deflated 55%) adding: lab05/lineOfx.m (deflated 50%) adding: lab05/boxOfx.m (deflated 52%) etc... >
Afterwards you'll have a file called
lab05.zip in your ~/cisc105 directory that you can submit on WebCT.
You can read about the various options of the zip command by typing
man zip at the Unix prompt.
lab05directory containing the appropriate information. This is optional, but highly recommended.
cp lab05.zip ~/temp
Now you can submit your work on WebCT, and you are done!
|step||what we're looking for||points|
distance.m should be copied verbatim from your lab03
testPowersOf2leX.m copied verbatim from web site, then
20 pts each (10 for correctness, 10 for programming style)
|step 10||lab05.txt diary file: following directions in scripting||10|
|step 11||lab05.zip file: following directions to correctly create zip file
(should unzip into a directory called lab05, not just a bunch of files)
|overall following of directions||student should follow the directions given||10|