Bielajew, A. F. - Introduction To Computers and Programming Using C++ and MATLAB - 2002
Bielajew, A. F. - Introduction To Computers and Programming Using C++ and MATLAB - 2002
using
C++ and MATLAB
Alex F. Bielajew
The University of Michigan
Department of Nuclear Engineering and Radiological Sciences
2927 Cooley Building (North Campus)
2355 Bonisteel Boulevard
Ann Arbor, Michigan 48109-2104
U. S. A.
Tel: 734 764 6364
Fax: 734 763 4540
email: bielajew@umich.edu
c 2000, 2001, 2002 Alex F Bielajew
This book arises out of a course I teach, a four-credit (52 hour) freshman-level course
Introduction to Computers and Programming being taught in the College of Engineering at
the University of Michigan. The book is in reasonably rough shape at this stage. It was
assembled from my lecture notes two years ago and is under constant revision. I may never
finish it! A wise person once said, Old age happens when you dwell more on the past
than on the future. By this definition, I have found eternal youth, insofar as this book is
concerned.
My educational objectives are quite simple. This is not really a course in computing. It
is a course in thinking, technical thinking, logical thinking, about formulating a problem, a
mathematical problem, a physics problem, a game, and then executing a solution and making
it work. I consider the computer and the ability to program it as a kind of laboratorya
laboratory to investigate practically, the theories and ideas of other technical courses. It is
possible, for example, to teach a lot of Calculus to students without ever mentioning the
word, and there are several examples throughout this book.
This course is not about syntax. Hence, the book introduces the minimum amount syntax
to get through a problem. Indeed, I even keep some syntax hidden, to encourage students
to discover their own algorithms. So, if you are thinking of using this book as a technical
reference in C++ or Matlab, I anticipate that you will be disappointed.
The greatest value in this book, if there is any to be found, is in the exercises, problems and
projects at the back of almost every chapter. The ideal way to learn a computer language
is to learn a little syntax and then try it out on a computer. The ideal way to think is
not to read about it, but to actually do it! The book reflects this. The material in the
chapters, separated from the exercises, is worse that useless, for reading the material and
not doing the problems is just a waste of time. Do the problems! Moreover, dont ask me
for the solutions! There is much more pedagogical value in a well-posed question than a
well-articulated answer.
OK, Ill step off my soap box now!
Several professors and many students who have contributed to the ideas put into this book.
Professor James Holloway and I have had endless discussion on the general problem of
teaching algorithmic thinking to freshman. We still have not come to any conclusions except
i
ii
that it is highly challenging and rewarding. As for how it actually gets done, well, to be sure
it is a works-in-progress. I spent a very enjoyable term co-teaching this course (the first time
I taught it) with Professor Ken Powell. Thanks, Ken, for nursing me through that first year!
Both Jamess and Kens diverse computational backgrounds are reflected to some degree in
this book.
I owe a debt of gratitude to the dozens of Graduate Student Instructors who have taught
with me on this course. One of them, Dan Osborne, deserves special recognition. He is one of
the most gifted and committed teachers I have ever encountered. Dan and I spent hour after
hour discussing the challenges of teaching computing and thinking skills to undergraduates.
To the 1300 or so undergraduates, mostly freshmen, who have taken my course: Every time
I teach this course I learn something newabout computing, about teaching, about the joy
of making an early deflection in a students career.
The support of the Dean for Engineering Undergraduate Education, Professor Gary Herrin,
I acknowledged warmly. Gary removes many of the roadblocks that could otherwise make
large-scale teaching odious. It is remarkable to have on ones side an administrator who is
more likely to say Yes! rather than No! to my numerous outrageous requests.
Finally, none of this would be possible without the support of my wife, Karen Vineberg. Your
strong support during the insanely busy term teaching this course is deeply appreciated. Yes
Karen, you are right, I do love teaching this course despite the long hours, the insomnia, the
lost weekends and lost vacations.
To all of them I give my thanks and to Karen, my love. Your efforts will go to help future
students.
AFB, July 17, 2002
Contents
2 Data representations 7
2.1 Bits, nibbles, bytes and words . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2.2 4-bit Binary, Hexadecimal and Decimal Digits . . . . . . . . . . . . . . . . . 9
2.3 Binary arithmetic . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.4 Converting from binary to decimal . . . . . . . . . . . . . . . . . . . . . . . 10
2.4.1 Whole numbers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
2.4.2 Real numbers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
2.5 Binary integer arithmetic on computers . . . . . . . . . . . . . . . . . . . . . 11
2.5.1 Twos complement integer arithmetic . . . . . . . . . . . . . . . . . . 12
2.6 32-bit Binary, Hexadecimal, Unsigned and Signed Integers . . . . . . . . . . 13
2.7 Problems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
iii
iv CONTENTS
5 Loops 83
5.1 The while loop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
5.2 The do/while loop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
5.3 The for loop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
CONTENTS v
5.4 Problems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
5.5 Projects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111
12 Graphics 367
12.1 Two Dimensional Plots . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 367
12.1.1 A basic plot . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 367
12.1.2 Using different line colors . . . . . . . . . . . . . . . . . . . . . . . . 367
viii CONTENTS
1
2 CHAPTER 1. INTRODUCTION TO THE COURSE
In our College of Engineering you will encounter faculty and staff who might otherwise have
been called Mathematicians, Physicists, Chemists and Biologists.
What is a computer?
Again, we appeal at first to some standard reference texts.
1. accepts some form of input (usually disorganized or of some highly specific nature),
2. responds to this input information in a pre-determined (programmed) way,
3. produces some form of output (usually more organized or coherent than the input)
Personal: Wristwatch, electronic car keys, phone, radio, GPS device, calculator, lap-
top...
In the home: Stove, refrigerator, freezer, microwave oven, clocks and timers, toaster,
coffee machines, thermostats, washer and dryer, TVs, VCRs, audio equipment...
Automotive: fuel delivery, air/fuel mixture, spark advance, brakes (ABS), traction con-
trol, suspension adjustment, climate control, navigation, computer-controlled driving
(coming soon)...
Digital computers?
Digital computers are the simplest of all! They only understand two things, which we
label 0s and 1s, or on or off, but more precisely, states of low and high voltages.
Computers switch between these two states very, VERY quickly. Modern run-of-the-mill
digital computers can throw about 100 billion switches per second! Thats enough to write
about 10 million pages of text in one second.
The input is rarely a collection of 0s and 1s, 011110000110... It can be in the form
of text that is converted to 0s and 1s or voltage that is digitized with an analog-
to-digital converter. (Musical recording, for example.)
The output is similarly rarely a collection of 0s and 1s. It can be 1D data (words,
numbers), 2D data (functions, charts, pictures, music), 3D data (video, surfaces, time-
evolving functions)...
The processing or computing or programming part is what the bulk of the course
is concerned with. The programming responds to the input in some pre-determined
way. In some digital computers the programming is fixed, for example, a digital clock
or a digital thermometer. In the most interesting cases, the program can be changed.
In this course we will learn to program programmable digital computers.
4 CHAPTER 1. INTRODUCTION TO THE COURSE
You can either start off the computer with the 0s and 1s in the right place, or, you use a pro-
gramming language. Programming languages provide the prescription, the pre-determined
steps that instruct the computer how to respond to the various input it gets. We will learn
two languages in this course.
C++ is a very popular (one of the most popular and common) language, a general-purpose
language that can be used for all aspects of computing. It is the best language to use
if one wants to teach many of the basic operations that a computer can perform.
MATLAB is a language that is suited for scientific and engineering applications, designed
for getting answers quickly, with the minimum of effort, with reasonable guarantee
that the answer is correct. It also provides graphical output with a minimum of effort.
How find the shortest distance between two points when the landscape is not flat?
If I take 10,000 steps in random directions, how far, on average, will I be from where
I started?
How can I do calculus on a computer (integrate, differentiate, find maxima and min-
ima)?
Where should I place a radiator in my room so that I am warm and do not have to
pay too much for the heat?
It is not really a course on operating systems, computer hardware, or the fine detail of
how computers work. We will discuss this but only enough to get the job done.
Educational Objectives
Engineering 101, Introduction to Computers and Programming, is intended to give you an
exposure to, and a chance to practice, algorithmic thinking. It does so by asking you to
actually solve problems using algorithms. This may be different from other courses that you
have taken, because we do not tell you exactly how to solve the assigned problems. Rather,
we provide you with tools that will allow you to solve them and some examples of how
problems are solved. But you must creatively assemble the solution yourself.
Note that neither C++ nor MATLAB languages per se are the keys to the course. We
teach you these languages so that you will have a means to express algorithms for execution
on a computer, but a great many other computer languages could have been selected to
support our central purpose of getting you to think about solving problems through a set
of procedural steps. Because programming languages such as C++ and MATLAB contain
many constructs and demand great attention to detail, it is easy to lose sight of the true
intellectual center of the course. But keeping a focus on algorithmic thinking will make
writing programs less difficult and less time consuming.
The educational objectives of Engineering 101 include:
Students who successfully complete Engineering 101 (receive a grade of C or better) should:
1.2 Problems
1. In the broad definition of computer in this chapter, how many computers can you
find: On yourself? In your room? In a car? In your home?
2. A typical 3rd grader is a lot smarter than any computer. They can read, do simple
math, play a musical instrument, memorize poetry and write stories. Generally, with
sufficient motivation, they will also do as they are told. How many ways could you
instruct a 3rd grader to determine the value of without the aid of a computer or
calculating device?
Chapter 2
Data representations
bit The digital computer processing hardware is made up of transistors each of which can
exist in only one of two possible states, a state of high voltage or low voltage.
This state of high/low (or on/off) is represented abstractly as 1/0 (one/zero). A bit
is some piece of microscopic (usually!) hardware that can exist in either of these two
states as determined by a programmer or computer designer. In addition to the voltage
states in a transistor in a computers memory chips or processing chips, there are many
others forms: magnetic domains in a floppy disk, hard disk or magnetic tape, pits
in a CD or DVD, holes in paper tape or computer cards. Nowadays, there are billions
or trillions of bits of various forms in a typical computer. A bit may be simple, but
it is usually so small, typically well below a micrometer across (1 micrometer = 106
m) that we can conceive of cramming billions of them into a relatively small volume
of space. Some bits, particularly those in the processing chips of a computer, can also
be made to change states very rapidly, well under one nanosecond. (1 nanosecond =
109 s.) So, we can do a lot of different things with lots of bits in a very short span of
time.
7
8 CHAPTER 2. DATA REPRESENTATIONS
word A word is a collection of bytestypically 4 for 232 = 4, 294, 672, 296 possible com-
binations. We can do a lot with all the different representations of words. We will
see, later in the lecture, how whole numbers can be associated with the various word
patterns.
The notion that many bits can conspire, in very large numbers, to produce wonderfully
intricate objects is illustrated in the following pictures of my dog, Matilda Skip Bielajew II.
(Yes, that is her real name!) The first picture was generated from a file that was about 12
Megabytes, containing 96 million bits. It looks like real life. Yet, even when we zoom a little,
we start to see the effects of the underlying bit structure. Look at how her whiskers appear
jagged. Under extreme magnification (one of her whiskers, again) we see that the picture is
made up of flat, uniformly colored tiles. Each one of these tiles is represented by 24 bits,
8 bits each for red, green and blue intensity, that, to all appearances, affords an apparently
uniform transition of color from tile to tile.
2.2. 4-BIT BINARY, HEXADECIMAL AND DECIMAL DIGITS 9
We will use this particular representation in doing some simple arithmetic in the exercises
and the assignments.
0 + ? = ? + 0 = ?
1 + 1 = 10
10 + 1 = 1 + 10 = 11
11 + 1 = 1 + 11 = 100
10 + 10 = 10 + 10 = 100
.
.
1111 + 111 = 111 + 1111 = 10110
.
.
.
The multiplication of fictional binary numbersbase-2 arithmetic looks like:
0 ? = ? 0 = 0
1 ? = ? 1 = ?
10 10 = 10 10 = 100
10 11 = 11 10 = 110
11 11 = 1001
.
.
.
1111 111 = 111 1111 = 1101001
.
.
.
The arithmetic procedure is the analogous to the more familiar base-10 system (that arose
simply because of our anatomy10 fingers). Additions of columns of numbers, subtraction,
multiplication, the procedure of long division, can be accomplished by analogous procedures.
There is no limit to how long a fictional base-2 number can be and we may have to carry
along some extra information with each numberits sign.
Humans are usually quite awful at doing binary arithmetic. If you are doing such a calcula-
tion, you can check by converting the binary numbers into their decimal equivalents.
In general, to convert a whole binary number to a whole decimal number, consider a binary
number of the form:
bn bn1 bn2 b2 b1 b0 ,
2.5. BINARY INTEGER ARITHMETIC ON COMPUTERS 11
where the bi s are either 0 or 1. We compute a decimal number using the following formula:
d10 = bn 2n + bn1 2n1 + bn2 2n2 b2 22 + b1 21 + b0 20 .
For example, the result of the two more difficult calculations above can be checked as follows:
101102 = 1 24 + 0 23 + 1 22 + 1 21 + 0 20 = 24 + 22 + 21 = 1610 + 410 + 210 = 2210
is the result of one of the additions [11112 (1510 ) + 1112 (710 )] above, while
11010012 = 26 + 25 + 23 + 20 = 6410 + 3210 + 810 + 110 = 10510
is the result of one of the multiplications [11112 (1510 ) 1112(710 )] above. Note that the
subscript 2 indicates a binary or base-2 number while the subscript 10 indicates a
decimal number.
where the bi s are either 0 or 1 and a period, . separates the whole part, bi where i 0 from
the fractional part, bi where i < 0. We compute a real decimal number using the following
formula:
It is not a whole lot different from the decimal numbers you are used to. However, sometimes
the formulae can look a little messy.
A string of 32-bits can represent many things but we will focus on hexadecimal, unsigned
and signed integers. These signed integers must also carry information as to the sign of the
number. Historically, there have been several ways to do this. The industry has settled
on 2s complement arithmetic because it simplifies the process of adding positive, negative
or mixed numbers. In this scheme, to negate a signed integer, one takes the complement
(change all the 1s to 0s and all the 0s to 1s) of the binary representation and adds 1 to
it. This is seen in the table at the end of this chapter.
Lets give the notation i to the complement of the integer i. So, for any i,
i + i = 11111111111111111111111111111111. That is:
any 32-bit pattern
+ complement of the above
= 11111111111111111111111111111111
and
11111111111111111111111111111111
+ 00000000000000000000000000000001
= 00000000000000000000000000000000
since the 33rd bit can not be set! In 2s complement arithmetic the expression i j is
calculated as i + j + 1. So you see, computers can not really add and subtract, they can only
add (and take complements)!
A few examples help illustrate the simplicity of the twos-complement scheme. Consider a
4-bit representation of the number 310 = 00112 and 410 = 01002 . There are two tricks you
should apply here: a) every time you see a negative sign in front of a bit pattern, i, to be used
in a calculation, convert it to a positive sign, change i to i + 1 and do the binary addition,
and, b) if a final result has a leading order (leftmost) bit set to 1, it is a negative number,
so, extract the minus sign and convert the resultant bit pattern j to j + 1.
See how easily it all worked out! This is why the two-s-complement approach has been
adopted. In order to handle negative integers one can convert them to their two-complement
counterparts and add. Otherwise, special circuitry would have to be developed for handling
negative numbers and that would be less efficient.
2.6. 32-BIT BINARY, HEXADECIMAL, UNSIGNED AND SIGNED INTEGERS 13
2.7 Problems
1. octal + octal = octal
Note: An octal is a number represented by only 3 bits.
Consider a fictitious computer, one that can only do 3-bit binary arithmetic. (Anything
past the 3rd bit can not be represented. See the notes for Lecture 2 for some related
examples.) Complete the following addition table, that is, add the octal in ith row to
the octal in the jth column and put the resultant octal in the box located at the ith
row and jth column. There are 3 examples worked out for you. For these examples,
show your calculations in long-hand.
Do your calculations in binary arithmetic and SHOW YOUR WORK! Quote your
results of your calculations in binary, integer, unsigned and hexadecimal integer repre-
sentations.
+ 0 1 2 3 4 5 6 7 8 9 A B C D E F
0 0 X X X X X X X X X X X X X X X
1 1 2 X X X X X X X X X X X X X X
2 2 3 4 X X X X X X X X X X X X X
3 3 4 6 X X X X X X X X X X X X
4 4 5 8 X X X X X X X X X X X
5 5 6 a X X X X X X X X X X
6 6 7 c X X X X X X X X X
7 7 8 e X X X X X X X X
8 8 9 0 X X X X X X X
9 9 a 2 X X X X X X
A a b 4 X X X X X
B b c 6 X X X X
C c d 8 X X X
D d e a X X
E e f c X
F f 0 e
18 CHAPTER 2. DATA REPRESENTATIONS
X 0 1 2 3 4 5 6 7 8 9 A B C D E F
0 0 X X X X X X X X X X X X X X X
1 0 1 X X X X X X X X X X X X X X
2 0 2 4 X X X X X X X X X X X X X
3 0 3 9 X X X X X X X X X X X X
4 0 4 0 X X X X X X X X X X X
5 0 5 9 X X X X X X X X X X
6 0 6 4 X X X X X X X X X
7 0 7 1 X X X X X X X X
8 0 8 0 X X X X X X X
9 0 9 1 X X X X X X
A 0 a 4 X X X X X
B 0 b 9 X X X X
C 0 c 0 X X X
D 0 d 9 X X
E 0 e 4 X
F 0 f 1
2.7. PROBLEMS 19
(a) In the 2nd column, write in the complement of the bit pattern in column 1
(b) In the 3rd column, write in the 2s-complement of the bit pattern in column 1
(c) In the 4th column, write in the 2s-complement of the bit pattern in column 3
(d) In the 5th column, put a check mark if the bit pattern in column 1 represents a
positive signed int.
(e) In the 6th column, put a check mark if the bit pattern in column 1 represents an
odd unsigned int.
(f) In the 7th column, put a check mark if the bit pattern in column 1 represents an
unsigned int that is divisible by 2.
(g) In the 8th column, put a check mark if the bit pattern in column 1 represents an
unsigned int that is divisible by 4.
(h) If the bit pattern in column 1 represents an odd unsigned int, write its unsigned
int representation in column 9.
9. A bit challenging
In the following table:
1) Convert the first 5 32-bit bit patterns to hex
2) indicate which bit patterns are divisible by 2 (/2)
3) indicate which bit patterns are divisible by 4 (/4)
4) indicate which bit patterns represent positive or negative integers in 2s complement
representation (+/-?)
5) indicate which bit pattern represents the largest integer in 2s complement repre-
sentation (>?)
6) indicate which bit pattern represents the smallest integer in 2s complement repre-
sentation, negative with the greatest magnitude (<?)
In this chapter we introduce algorithms and ways with which algorithms can be represented.
At the end of the chapter, we also talk a little about computer architecture, as a way of
illustrating the operations that can happen inside a computer, when a part of an algorithm
is executed.
An algorithm usually has a START point and a STOP point. Certainly any algorithm
we shall encounter in this book will. The START may require some inputs and the
STOP may provide some output.
An algorithm is made of individual instructions.
An instruction consists of a well-defined operation usually on some input (what the
instruction receives) and usually producing output (what the instruction produces).
Each instruction is well-defined and its outcome predictable if the instruction operates
on valid input.
There is a direction of logic flow or sequencing. Once an instruction is executed, it
passes control to another instruction.
There can only be a finite set of instructions.
When executed (with valid input) an algorithm is guaranteed to terminate in a sensible
way.
23
24 CHAPTER 3. ALGORITHMS AND PSEUDOCODES
START
STEP 1
STEP 2
STEP 3
STOP
The above figure is a representation of a simple sequence of 3 steps with a beginning and an
end. The START and STOP are represented by circles. A sequence step is represented by
a rectangle. The logic flow is indicated by lines and arrows. This kind of representation is
called a flowchart or schematic diagram. It looks a lot like a circuit diagram in electronics.
START
Step 1
Step 2
Step 3
STOP
IF such-and-such THEN DO
this-and-that
OTHERWISE DO
something-else
One could do the same thing with a flowchart, and it would look like:
YES SUCH NO
&
SUCH
THIS SOMETHING
& ELSE
THAT
Note that we have introduced a new shape to handle the case where, depending on the input,
a decision is made and the logic flow can follow two different paths. This is represented by a
diamond shape. A branch statement or a decision statement is characterized by only one
path in and always two paths out.
The stuff between STEP 3 and JUMP TO: ITEM 3 inclusive, defines a loop. This is
represented in a flowchart as follows with the direction of logic flow made clear with the lines
and arrows.
ITEM 3
JUMP TO
ITEM 3
2. If the day is not Sunday, have your usual boring bowl of Granola. For added excitement,
slice in half a banana. Otherwise,
(a) In a big bowl, whisk together 1 and 1/2 cups white flour and 2 heaping teaspoons
of baking powder.
(b) In a separate bowl, beat two whole eggs (no shells please) together for one minute
or so.
(c) Add 1 cup of milk, preferably skimmed, to the eggs and mix.
(d) Add 1 tablespoon of Canola oil, 3 tablespoons of maple syrup, and one teaspoon
of vanilla to the milk and eggs and mix.
(e) Add the wet stuff to the dry stuff.
(f) Take a big spoon and,
(g) mix the stuff in the big bowl one whole turn.
(h) If there are lots of lumps in the mixture , go back to step 2.(g), otherwise go to
step 2.(i). Technical note: Dont go overboard and make it completely smooth.
Leave it a little lumpy for texture.
(i) Slice in a Granny Smith apple (no peel) and (optionally) a half cup of frozen
cranberries (well rinsed).
(j) Add a little bit of Canola oil to an electric fry pan preheated to 350 F. Put in
just enough to coat the bottom of the pan.
(k) Put the pancake dough into the pan, making approximately four 34 diameter
circles. Turn the heat down to 300 F. Fry for exactly 3 minutes with the pan
covered, flip and fry for 3 more minutes with the pan uncovered.
(l) Take them out of the frying pan and place on a napkin to absorb excess oil.
(m) Eat with maple syrup and sliced strawberries on top. I DARE you to eat more
than 3! (It has never been done...)
Definitions: x is an unknown real number, A, B, C are fixed constants that can take on any
valid real value. We are trying to find the values of x for which Ax2 + Bx + C is zero. If we
plot the function f (x) = Ax2 + Bx + C, a parabola, it can look as shown in the figure below,
for certain choices of A, B, and C. The x-axis can intersect the curve f (x) = Ax2 + Bx + C
only 0, 1 or 2 times, depending on the values of A, B, and C.
NO SOLUTION
X
1 SOLUTION
X
2 SOLUTIONS
X
Ax2 + Bx + C = 0
B C
A x2 + x + = 0 N.B. A 6= 0
A A
B C
x2 + x + = 0
A A
2 2
B B B C
x2 + x + + = 0
A 4A2 4A2 A
30 CHAPTER 3. ALGORITHMS AND PSEUDOCODES
B B2 B2 C
x2 + x+ =
A 4A2 4A 2 A
B B2 B 2 4AC
x2 + x + =
A 4A2 4A2
B 2 B 2 4AC
x+ =
2A (2A)2
B B 2 4AC
x+ = N.B. B 2 4AC 0
2A 2A
B B 2 4AC
x =
2A 2A
B B 4AC 2
x = A 6= 0, B 2 4AC 0
2A
So, under the some circumstances (A 6= 0, B 2 4AC > 0), we have two solutions:
B + B 2 4AC B B 2 4AC
x= and x =
2A 2A
corresponding to the last case in the preceding figure.
What if A 6= 0, B 2 4AC = 0? We have one solution:
B
x=
2A
corresponding to the middle case in the preceding figure.
What if B 2 4AC < 0? No real solution. This corresponds to the first case in the preceding
figure.
What if A = 0? Re-analyze!
START A, B, C are inputs, known to be real, fixed constants and x is the output, expected
to be real but unknown at the start
3.8. SOME EXAMPLES 31
IF (B 2 4AC < 0)
PRINT (No solution because B 2 4AC < 0)
STOP
ELSE (i.e. B 2 4AC 0)
IF (A 6= 0)
IF (B 2 4AC = 0)
x = B/(2A)
PRINT (One solution: x, because B 2 4AC = 0)
STOP
ELSE (i.e. B 2 4AC > 0)
x1 = (B + B 2 4AC)/(2A)
x2 = (B B 2 4AC)/(2A)
PRINT (Two solutions are: x1 and x2 )
STOP
ELSE (i.e. A = 0)
IF (B 6= 0)
x = C/B
PRINT (Only one solution x, because A = 0)
STOP
ELSE (i.e. B = 0)
PRINT(No solution because A = 0 and B = 0)
STOP
END OF ALGORITHM
Note:
START
IS N
NO
B2-4AC >- 0 SOLUTION STOP
?
IS N IS N NO
A =/ 0 B =/ 0 SOLUTION STOP
?
?
Y Y
IS X = -C / B
Y
B2-4AC = 0
?
X = -B / (2A) PRINT X
N
X 1 = -B + B2-4AC
2A PRINT X STOP
X 2 = -B - B2-4AC
2A STOP
PRINT ( X 1 , X 2 )
STOP
Note that, although there is no reason to expect it, the flowchart designer expects that there
will be two real solutions everytime. This is reflected in the flowchart by this case running
vertically down the page, with the expections hanging off to the right. This makes the
flowchart particularly easy to read.
3.8. SOME EXAMPLES 33
Before you read this section, if you have never had any experience with programming, the
statement S = S + 1 should justifiably seem to be completely wrong, since mathematically
it is equivalent to saying 0 = 1! Just cancel the Ss from either side! So, if this is the case,
kindly go and read the next section An aside on computer architecture and then come
back. Although mathematical statements and computer code statement may look the same,
they are completely different. Mathematics expresses an idea, while a line of computer code
represents an operation, or a set of individual operations.
START
N FIXED NUMBER
S IS UNKNOWN
S=1
S=S+2
S=S+3
.
.
.
S=S+i
.
.
.
S=S+N
PRINT S
STOP
START N is an integer (fixed), S is an integer that will contain the sum . At the start, S is
initialized to 1, that is, its starting value will be 1. Another integer, i, is employed to
contain the value that is to be added to S. It is initialized to 1.
END OF ALGORITHM
START
N FIXED NUMBER
i = 1; S = 1
i=i+1
S=S+i
NO
i=N?
YES
PRINT S
STOP
There is an even better way! There is a mathematical solution to this that was discovered
by Gauss (Karl Friedrich Gauss (17771855 AD)) as a schoolboy!
N(N + 1)
S=
2
36 CHAPTER 3. ALGORITHMS AND PSEUDOCODES
If N is even:
Problem: Compute P = k N .
A very, VERY, dumb way (but one that works):
START k is an integer or a real (fixed), N is an integer (fixed) and P is an integer or a real
number (unknown)
P = k
P = P k
P = P k
.
.
.
P = P k (for the ith statement)
.
.
.
P = P k (for the Nth statement)
PRINT(P)
END OF ALGORITHM
Here is the flow chart for the very, VERY, dumb way:
3.8. SOME EXAMPLES 37
START
N FIXED NUMBER
k FIXED NUMBER
P IS UNKNOWN
P=k
P=P*k
P=P*k
.
.
.
P=P*k
.
.
.
P=P*k
PRINT P
STOP
Start of loop:
38 CHAPTER 3. ALGORITHMS AND PSEUDOCODES
End of loop:
PRINT(P)
END OF ALGORITHM
START
Here is the flow chart for the better way:
N FIXED NUMBER
k FIXED NUMBER
i = 0; P = 1
i=i+1
P=P*k
NO
i=N?
YES
PRINT P
STOP
START
N FIXED
k FIXED
P = 1 (PRODUCT)
(N < 1)
NO
N>
- 1? PRINT P STOP
YES
YES NO
N even
?
N=N/2 N=N-1
k=k*k P=P*k
MEMORY The memory physical place in the computer where bit patterns are stored.
Memory is best thought of as a stack of words, 32-bit bit patterns.
VARIABLE A symbol for a certain bit pattern (a 32-bit integer, say) that the programmer
can define and change at will in a program. The symbol (S in this case) really refers
to the location in memory where the bit pattern is stored.
CONSTANT A symbol for a certain bit pattern that the programmer can define and use
but not change.
CPU The Central Processing Unit in a computer. The CPU is the boss. It follows the
steps in a program and tells all the other parts of a computer what they should be
doing. It is the controller.
REGISTER A special place in the CPU where bit patterns are stored.
ADDER A functional unit in a computer (usually located right on the CPU chip) that
performs additions on 32-bit bit patterns.
MEMORY
00000000000000000000000000000000
S: 00000000000010010000100000100000
ADDER 00000000000000000000000000000000
00000000000000000000000000000000
C: 00000000000000000000000000000001
CPU 00000000000000000000000000000000
R1 R2 R3 R4 00000000000000000000000000000000
3.10. PROBLEMS 41
FETCH S,R1 Copy the bit pattern that is stored at the location referred to by S and put
it in the 1st CPU register R1.
FETCH C,R2 Copy the bit pattern that is stored at the location referred to by C and put
it in the 2nd CPU register R2. Previously in the program, the constant C would have
to have been defined and the bit pattern for C (00000000000000000000000000000001)
would have to have been stored in C.
ADD R1,R2,R3 Copy the constants of the bit patterns stored in R1 and R2 into the
ADDER, do the binary arithmetic and copy the result into the 3rd CPU register R3.
STORE R3,S make a copy of the bit pattern in the 3rd CPU register R3 and place it in
the memory location referred to by S.
So, just the simple increment (add by 1) of a variable results in 4 operations performed by
the CPU. The following steps are exactly what an assembly language program would have
to do to interpret the statement S = S + 1. Remember that when we write statements like
S = S + 1 it is really a shorthand for a set of steps that a computer has to carry out. We
will be clear in the future as to what is math and what is computer language. Math script
will be used for math (e.g. S = S +1) while type script will be used for computer instructions
(e.g. S = S + 1).
3.10 Problems
1. The trinity of algorithmic design
What are the three most important capabilities that are needed to construct algo-
rithms?
2. What is an algorithm?
In 35 words or less, answer the question, What is an algorithm?.
3. What is an algorithm?
The three pillars of algorithm design are 1) sequencing, 2) branching, and 3) looping.
In 25 words or less for each, describe what they mean.
That is:
What is sequencing? (25 words or less)
What is branching? (25 words or less)
What is looping? (25 words or less)
5. In the 70s, man, if you were not hip, you were ...
Here is an algorithm in pseudo-code:
START
OUTPUT Enter a positive integer
INPUT N
i=1
WHILE (i i < N)
i=i+1
END WHILE
IF (i i = N)
OUTPUT YES
ELSE
OUTPUT NO
END IF
STOP
For which of the following inputs will the algorithm say YES?
(a) 28
(b) 36
3.10. PROBLEMS 43
(c) 54
(d) 81
* * * * *
* * * * * * * * * *
3 * * * * * * * * * * * *
6 * * * * * * * * * * * *
10 * * * * * * * * * *
15 * * * * * *
21
Here is an algorithm that is attempting to detect triangularity in the input. But it has
a bug. Fix the algorithm.
START
OUTPUT Enter a positive integer
INPUT N
i=1
S=0
WHILE (S < N)
i=i+1
S =S+i
END WHILE
IF (S = N)
OUTPUT Triangular
44 CHAPTER 3. ALGORITHMS AND PSEUDOCODES
ELSE
OUTPUT Not triangular
END IF
STOP
8. De-Gauss this!
In this chapter we learned Mr. Gausss formula for the computation of the Nth trian-
gular number:
N(N + 1)
1 + 2 + 3 + ... + N =
2
START
OUTPUT Enter a positive integer
INPUT N
i=1
WHILE [(i (i + 1))/2 < N]
i=i+1
END WHILE
IF [(i (i + 1))/2 = N]
OUTPUT Not triangular
ELSE
OUTPUT Triangular
END IF
STOP
S = 1 x + x2 x3 + x4 + (x)N
3.10. PROBLEMS 45
where x and N are inputs and S is the sum, an output. You must express your
algorithm in terms of a loop that is traversed N times. Express your algorithm in
terms of pseudocode and a flowchart.
x x2 x3 x4
S =1 + + +
1! 2! 3! 4!
Let x and N, the number of terms on the right hand side, be inputs to the algorithm
and S, the sum, be the output. Note the use of the factorials in the above sum. Ex-
press your algorithm in terms of pseudocode and a flowchart. Note that the algorithm
to raise x to a power is given in Chapter 3, Section 5 of the book.
Hint: The most efficient way to solve this problem is to rewrite S in the following
fashion:
S = s0 + s1 + s2 + s3 + s4 +
46 CHAPTER 3. ALGORITHMS AND PSEUDOCODES
x x3 x5 x7
S= + +
1! 3! 5! 7!
Let x and the number of terms on the right hand side be inputs to the algorithm and
S, the sum, be the output. Note the use of the factorials in the above sum. Express
your algorithm in terms of pseudocode and a flowchart.
3.11 Projects
1. Follow the bouncing ball
You will describe an algorithm as if you were going to program it on a computer, that
is, you will specify a set of instructions that even a machine can understand. Your
algorithm should specify its purpose, the input data (if any), the output data (if any),
and the set of steps that comprise the algorithm itself. The algorithm should include
instructions on how to start and end. You can assume that the machine on which the
algorithm will be implemented can store variables, loop, and do branches.
The problem is to determine the total distance a ball travels having been dropped from
a height h (and traveling a total distance h on its way to the floor) and rebounding to
a fraction of h which we will call ch (and traveling a total distance h + ch). c is called
the coefficient of restitution. The ball will then drop to the floor (total distance =
h + 2ch) and bounce up to a height c2 h (total distance = h + 2ch + c2 h) and so on.
You can assume for simplicity that the ball is a point, that is, its diameter is exactly
zero (a mathematical fiction to make our lives easier) and that c falls anywhere in the
region 0 < c < 1. Write an algorithm that determines the distance the ball travels
before coming to a rest. You can make any reasonable assumption you like about what
at rest means for the ball. However, the assumption has to be reasonable and
justifiable either on the basis of numerics, mathematics or physics. This is a subtle
point that is discussed below and is discussed in class.
This problem has an exact mathematical solution:
1+c
d=h
1c
that you must not employ in your algorithm to determine the total distance traveled.
You have to obtain the solution by developing an algorithm that sums individually
every bounce of the ball.
Some discussion:
A ball made from putty will have c = 0 and an ideal ball (which does not really exist
in reality) would have c = 1. A fresh out-of-the-can tennis ball has c = 0.5 or so, an
old tennis ball has c = 0.25 or so. A ping-pong ball has c = 0.90 or so.
This problem is very much like Xenos paradox. The paradox is that mathematically
the total distance traveled by the ball is finite (as long as c is less than 1) but math-
ematically the total number of bounces is infinite! However, after many bounces the
recovery distance becomes so small that accumulating them really does not matter in
any practical sense any more. If digital computers could really represent real numbers
to infinite precision then it would be possible to write an algorithm that accumulates
the distance properly but it would never stop unless we introduced some artificial means
of stopping th execution. Part of the purpose of this exercise is to get you thinking
48 CHAPTER 3. ALGORITHMS AND PSEUDOCODES
about this paradox, to realize that computers can only provide an approximation to
mathematical fiction and physical reality.
Chapter 4
//File: goBlue.cpp
#include <iostream>
int main(void)
{ cout << "Go Blue!\n";
return(0);
}
Comments Comments start with /* and end with */. For example,
/* This is a comment */
49
50 CHAPTER 4. GETTING STARTED IN C++
Comments are put there for humans only. They do not affect or modify what the
computer does. The computer does not care if you comment or not. But humans
do, especially your Lab Instructors and other people who hand out grades or
pay your salary. Comments should explain what you are trying to accomplish and
how you are going about doing it. It is appropriate and usually correct to assume
that the person reading your code is a complete idiot and that you have to explain
in detail what you are doing. After you have forgotten how or why you programmed
your own code, you will find your own comments very useful to understand what you
have done. The start of any program or program segment should begin with a few
lines of explanation, along with an identification of the programmer and the date it
was created. Put comments through the rest of the code wherever you think that the
reader (aka the idiot) might need some explanation. Less is not more in this case. But,
dont go overboard too far. When in doubt, comment, comment, comment.
Comments can begin and end anywhere and can span more than one line.
// This is also a comment, from the "//" to the end of the line
which is useful when your comment is only one line or you want a comment to start
somewhere in a line and continue to the end of the line.
Use both kinds of comments and make your code readable.
Preprocessor directives Preprocessor directives instruct the compiler in advance of the
actual compilation of your code. Preprocessor directives are indicated by a # be-
ginning a line. In this case the preprocessor directive
#include <iostream>
instructs the preprocessor to include the contents of the ANSI standard library file
iostream. This header file contains other #include statements that call other library
files that define the standards C++ input and output functions.
There are other common header files. We shall soon encounter cmath which is included
via the preprocessor directive
#include <cmath>
which defines a lot of the common math functions. There are other types of prepro-
cessor directives called symbolic constants and macros which we shall encounter
later.
If you want to have a look at these library files, look in the directory called
/usr/include/g++-2
where they reside. Boredom alert! This is not for the faint-of-heart!
4.1. SIMPLE INPUT/OUTPUT (I/O): A FIRST PROGRAM IN C++ 51
using namespace std; Tells the compiler that we will be using that standard namespace
in the file that contains the line
using namespace std;
All this really means is that standard library files and definitions are being used. It is
possible to define your own namespaces if you want to make sure that your variables
and definitions do not conflict with either the standard ones, or someone elses, someone
working on the same project. For this course, we shall be using the standard namespace
for everything we do. If you go on to work in a professional programming environment,
writing software by teams, you will almost certainly be using your own namespaces.
int main(void){} All C++ programs begin processing at the first executable statement in
main. The ()s indicate that main is a block of code called a function. The int in
front of main declares main to be a function that is expected to return an integer.
(More on this later.) main is a special function that the operating system recognizes
as the place to begin execution of a C++ program.
The lines of code in between the {}s is called the function body. It is considered good
programming practice to indent the text in the function body by a certain amount of
space. Horstman recommends 3 spaces which is reasonably pleasing to the eye. We
will adopt this convention for this course. In our example, the function body starts
with the statement
which instructs the C++ standard library function cout function to print the series
of characters Go Blue! (not including the double quotes) to the screen and then
positions the cursor at the beginning of the next line. This positioning is effected by
a special sequence of characters \n called an escape sequence. Escape sequences are
necessitated when special characters are required or to undo the meaning of special
characters, like the double quote () in the cout statement above. Here is a list of
some commonly used escape sequences employed in cout statements.
cout <<
"\n\n\t\"Go\t\t\\\n\t\t\t\tBlue!\"\a\a\a\r";
which throws 2 newlines, goes to the first tab stop, prints a double quote followed
by Go, advances two more tab stops writes a backslash, throws a newline, goes to
the third tab stop and prints Blue! followed by a double quote, sounds the alarm
3 times (You will probably only hear one beep, depending on your computer.) and
issues a carriage return. Because a new line was not thrown, further keyboard input
could overwrite the Blue! text. This just goes to show how far a professor will go to
contrive an example. Here is what the output looks like:
"Go \
red% Blue!"
Note that the statement starting with cout is terminated with a semicolon (;). This
is a special character in C++ called a delimiter that signifies the end of a statement.
There can be more than one statement per line in a C++ code or a single statement
can span several lines. Generally it is considered to be good programming practice
to put at most only one statement per line of code. If a statement is long, put it on
several lines, space things nicely, and indent the carry-over lines 3 spaces relative to
the first line, like in the example above.
return(0); When this line is encountered, processing in the CPU returns to the operating
system. Since main is a function of the int type, an integer value must be returned
to the process that called it, in this case the O/S. A return value of 0 usually means
normal execution, by convention. A return other than 0 can be treated as an error
condition by the O/S. For example, if your program had prompted for user input and
the user typed in something that the program was not prepared to process, one could
signify this to the O/S by returning a 1, for example,
return(1);
You can have as many returns as you need in a C++ code, just as you can have many
stop points in an algorithm.
The C++ compiler is another program that converts text instructions into binary code that
a computer understands. Compilers have evolved over a long period of time. The original
computers (dating to the middle and late 40s) were actually programmed in binary code
that was processed by the computer directly. This was an extremely laborious process. Early
on it was recognized that it would be easier to program in a more human-compatible way,
in a text-based format, and convert this into machine code using a compiler.
The origins of C++ date back to the late 60s and early 70s to the C language. The original
intent for C was to develop a language for writing computer operating systems. Operating
system (OS) code is special software for allowing users and programs to interact with data
stored on a computer and instructs the operational units of a computers what to do with
this data. Later, in the 80s and 90s, C++ was developed as an evolution of the C language.
(Any C++ compiler will compile C code.) The number of improvements is very greattoo
many to mention.
C++ code is designed to be as hardware-independent as possible so that C++ code can
migrate between different computer architectures. C++ code is translated into assembler
or assembly language which represents a text version (i.e. human-readable) version of bi-
nary code. Assembly language is always machine dependent and addresses (speaks to) the
computer hardware and it subcomponents. C++ is a higher-level language that deals with
hardware and data in a more abstract way.
C and C++ have evolved beyond their original intent as OS-builders, although this role is
still very important. C and C++ are powerful general-purpose languages for most aspects
of computing. It is probably true that C and C++ are the most commonly-used computer
languages in the world. C++ is certainly the one that is taught the most. There are other
high-level languages for special purpose applications in business and numerical computa-
tion but probably C++ will supplant these as new business and numerical computation
applications evolve.
After an algorithm is developed through the conceptual, pseudocode and flowchart process, a
C++ program (or other computer language program) is written. During a C++ compilation
and execution, several steps occur:
Edit A human writes a computer program, e.g. goBlue.cpp Any editor will suffice. Com-
mon unix editors are vi, emacs, pico, nedit or kwrite. Use whatever you like. Your
lab instructor will inform you of your options and probably ask you to stick with one
of these.
Preprocess, precompile Preprocessor directives, like #include and #define are handled.
This can be inclusion of files or substitution of text throughout the C++ program.
54 CHAPTER 4. GETTING STARTED IN C++
Compile After the preprocessor the compilation converts the code to object code also known
as binary code. There are actually several stages. The first is the parsing stage where
the compiler checks the syntax of your code. If this stage is passed successfully the next
stage is the production of the assembly code from the C++ code which is syntax-error
free. Then the assembly code is converted to binary code, also called object code.
Link After the object code is created the link stage is entered. At this point, references
to functions that may have been referenced in the C++ program are established.
These missing parts, in the form of object code, are either put in place directly where
referenced (this is called static linking) or their transfer locations are established so
that processing can transfer to these locations and be resumed. This is called dynamic
linking. The file created by the linker is called the load module. By default, the load
module is called a.out by the unix operating system. A user can override this name if
desired.
Load The loader takes the load module (usually located on disk) and puts it into memory in
a place where the operating system expects to see executable code. On a unix system
the leading phase is started when a user types the name of the load module resident
on disk.
Run In the run phase, the binary code in the memory-resident load module is transferred to
the central processing unit (CPU) for execution. The load module contains instructions
for the CPU that directs it to assign tasks to the various operational units of the
computer. The load module also contains data and references to data that are to
be operated on. The run phase is where conceptual errors in a computer program
are exposed. Code that has incorrect syntax, and syntax errors are quickly found by
the compilers parser, are usually easy to correct. Code that has correct syntax but
incorrect design are much harder to find. This is where pseudocode and flow charts
can come to the rescue.
THINK
TYPE IT IN / EDIT
STEAL AS MUCH
AS POSSIBLE
FAILURE
1) PRECOMPILING
2) PARSING
COMPILE
3) CREATES OBJECT
LINK / CREATE
LOAD MODULE FAILURE
RUN
REFINEMENT
SUCCESS!
//File: integerMath.cpp
#include <iostream>
56 CHAPTER 4. GETTING STARTED IN C++
int main(void)
{ int i1 = 5; // Define and initialize
int i2 = 2; // Define and initialize
int iResult; // Define only
return(0);
}
int i1 = 5;
is a declaration statement. The name i1 is an identifier for the variable i1. This declaration
statement specifies that i1 is an int, a signed integer. It also provides an initialization for
i1, giving it the value of 5.
An identifier is a series of characters you can type at a keyboard that can consist of letters,
digits, and underscores ( ). It is a bad idea to start an identifier with an underscore, even
though it is legal, because most identifiers in libraries accessed by C++ use this. An identifier
can not start with a digit, however. According to the draft ANSI C++ standard, an identifier
may be any length. ANSI [American National Standards Institute] C++ is a built upon
ANSI C, and in ANSI C only the first 31 characters are required to be recognized by C
compilers conforming to the ANSI standard for C. Different C++ compiler writers determine
how many characters in an identifier are significant. I recommend NOT using more than
4.4. INTEGER MATH IN C++ 57
31, for safety. Beyond the limit of 31 or greater, your compiler may treat the characters
beyond it as significant or insignificant (i.e. ignores them). For absolute safety, use 31
characters or less. Identifiers in C++ are case sensitive so that i1 and I1 are recognized
as different variables. Unless your program is very short, you should name your identifiers
in some recognizable wayit cuts down on the amount of commenting you have to do. I
also like humpback notation, numberOfStudents, rather than number_of_students. Note
that humpback identifiers start with lowercase letters (usually) and new words within the
identifier start with an uppercase letter. I find underscores in the middle of identifiers ugly,
wasteful and hard to type.
The statement
int i2 = 2;
int iResult;
iResult = i1 + i2;
contains two mathematical operators, = and +. The operator = is called the assignment
operator . Do not call it the equal sign! The assignment operator assigns the result of
the operation(s) to the right of it to the value of the identifier to the left of it, iResult in
this example. = is called a binary operator because it operates on only two quantities, the
variable to the left which gets the assignment and the quantity to the right that provides
the assignment (after the other mathematical operations are completed).
The operator + is called the addition operator . It is also a binary operator and provides the
mathematical sum of the quantities to its left and right.
There are 4 other binary operators to consider now, the subtraction, -, the product, *, the
division, /, and the the modulus, %. Of these the division requires special mention with
58 CHAPTER 4. GETTING STARTED IN C++
regards to its operation with integers. The integer division returns the integer part of the
result. For example, 5/2 = 2, not 2.5. The remainder of a division can be obtained from the
modulus function %. Thus 5 % 2 = 1.
The various mathematical operations, when employed within the same statement, follow
certain ordering rules. These are called the rules of precedence. The *, / and % operations
take precedence over + and -. *, / and % have the same precedence, and + and - have the
same precedence as well. For operators with the same precedence, the order of operation is
left to right. For example,
1 + 10 * 5 - 9 / 3 = 1 + 50 - 3 = 48
(1 + (10 * 5) - (9 / 3)) = 1 + 50 - 3 = 48
is quite different.
Summarizing, the order of precedence is
The statement
prints the characters 5 + 2 = to the screen then the value of iResult and then sends
the newline escape sequence. There are more flexible ways of printing things to the screen
and we shall encounter these shortly. Note how we can cascade the << operator for cout.
An equivalent way of accomplishing the same thing would be:
which is a little harder to read. Break up your output statement like this only for neatness
and readability.
//File: floatMath.cpp
#include <iostream>
int main(void)
{ cout << "Input the 1st floating point number: ";
float f1; // Declare the 1st float
cin >> f1; //and read it in
if (0 == f2)
{ cout << "Division by zero not permitted!\n";
return(1);
}
else
{ fResult = f1 / f2; // division
cout << f1 << " / " << f2 << " = " << fResult << "\n";
return(0);
}
}
60 CHAPTER 4. GETTING STARTED IN C++
float f1;
}
.
.
.
else if (logical expression N + 1 )
{
STATEMENT BODY N + 1
}
else
{
STATEMENT BODY N + 2
}
There are many forms of the if/else if/else construct:
If the STATEMENT BODY consists of one and only one statement, then the surrounding
{}s are optional. (It can help with clarity of programming to keep them, however.
Their use is highly recommended.)
At most one and only one of the STATEMENT BODY s can execute within an if/else
if/else construct can be executed
Processing control passes to the statement immediately following the if/else if/else
construct after execution of one of the STATEMENT BODY s.
If the if/else if or if form is used, it may happen that none of the logical condi-
tions is satisfied. In this case processing control passes to the statement following the
construct.
T
?
F
?
F
?
T
T
4.7. LOGICAL EXPRESSIONS 63
F
?
F
?
T
T
if (1)
cout << "This would always print,\n";
else if (0)
cout << "whereas this would NEVER print\n";
Here are some of the logical operators and their order of precedence
64 CHAPTER 4. GETTING STARTED IN C++
Lets return to the example of solving the quadratic equation, Ax2 + Bx + C = 0 that we
studied in flowchart and pseudocode form in Lecture 3. If we look at the pseudocode on
page 7 of Lecture 3 we see that the ifs are nested and we would probably, at first try, write
a code that looked something like the following, using only ifs and elses:
//File: quadratic.cpp
#include <iostream>
#include <cmath>
int main(void)
{ float a,b,c; // Declare the constants...
cout <<
"Calculating roots (x) of the equation\n"
<< a << "*x*x + " << b << "*x + " << c << " = 0...\n";
However, by using else ifs we can make the code look less nested and complicated. The
nesting is really still there and we have to remember that when we pass into an else if
that the if condition above it is still false! However, else ifs make the coding look neater
and easier to read.
//File: quadratic2.cpp
#include <iostream>
#include <cmath>
int main(void)
{ float a,b,c; // Declare the constants...
cout <<
"Calculating roots (x) of the equation\n"
<< a << "*x*x + " << b << "*x + " << c << " = 0...\n";
66 CHAPTER 4. GETTING STARTED IN C++
Here are more of the logical operators and their order of precedence:
The AND and OR operators work as follows. Imagine that two logical expressions evaluates
to either T (TRUE) or F (FALSE). This is the result of the && and ||s operating on them.
4.7. LOGICAL EXPRESSIONS 67
(T && T) == T
(T && F) == F
(F && T) == F
(F && F) == F
(T || T) == T
(T || F) == T
(F || T) == T
(F || F) == F
Sometimes these tables are difficult to remember, at least as abstract concepts. This is
helped somewhat if we substitute numerical values for T (1) and F (0).
(1 && 1) == 1
(1 && 0) == 0
(0 && 1) == 0
(0 && 0) == 0
(1 || 1) == 1
(1 || 0) == 1
(0 || 1) == 1
(0 || 0) == 0
Once we do this we realize that the result of (A && B) is the lower value of either A or B. The
result of (A || B) is the higher value of either A or B. It is no more complex than that! And
this is, in fact, how the electronic circuitry works in a computer during the interpretation of
logical expressions.
Some examples:
int i = 5;
if (0 > i || 10 <= i)
cout << i << " is either negative, or has more than one digit\n";
When logical operators and arithmetic operators are mixed in a single expression, the order
of precedence is as follows. Above all, the contents of parentheses are evaluated starting with
the innermost. Then the arithmetic operators get interpreted in the order already discussed.
Finally, the logical operators get interpreted in the order already discussed. Here is the table
for precedence for both arithmetic and logical expressions.
When in doubt, use parentheses. When not in doubt, use parentheses anyway. The
person reading your code may have forgotten all but the first rule of precedence, parentheses
are interpreted first. This will make your code more readable and understandable.
In fact, that is the convention I have adopted in almost all of my programming, put paren-
theses around every logical sub-expression in any logical expression that contains more than
one logical operators. I also put parentheses around any arithmetical sub-expression in a
mixed arithmetic/logical expression.
Heres an example of a mixed arithmetic and logical expression. Use the rules of precedence
stated above to see how the following statement is evaluated:
if (i*j == i*i + j*j || i - j <= i*i - j*j && i + j <= i*i + j*j) ...;
The ordering of && and || is also quite important. For example, using the rules of precedence
the above could collapse to 1 || 1 && 0 which is 1 or TRUE. However, if you mistakenly
thought that the || is evaluated first, you would guess that the answer should be 0 or FALSE,
and that is the wrong answer in this case.
4.8. PROBLEMS 69
4.8 Problems
1. An essay-type question? In a computer1 class!
Answer the following questions in your own words...
2. Basic Arithmetic
Write down the value that is assigned to the variable on the left-hand side of each of
these expressions. The variables i and j are ints; x and y are floats.
i = 1 + 2*3/4+5;
x = 1.0 + 2.0 + 3.0/4.0 + 5.0;
j = (1 + 2)*3/4 + 5;
y = (1.0 + 2.0)*3.0/4.0 + 5;
y = 1 + 2 + 3/4 + 5;
x = 1 - (static_cast<int>(6*5/4.0*3))/2;
(1 || 1 && 0 || 0)
(0 > i && 10 < i)
(0 > i || -10 < i)
(2*i + 1)
(4*i%2 && 1)
(2*i + 1 || i/2)
int i, j, k = 0;
int i, double j;
int i0 = 4, f = -1, k=0;
int i; float _0j;
int i j k l m;
int The, Wolverines, Are, Rated, Number, 3;
float f, F, _000000, Wolverine;
int i,j ; i == 1 && j || 3%2;
int static_cast<float>(N);
i = -i + -j;
i + j = f;
x = x*x + 3;
y = x^2 + 3;
y = a x + b;
z = x + y123;
z = x + 123y;
for(i = 0,i <= 10,i = i + 1) cout << "OK?\n";
while(thisIsTrue) cout << "OK?\n";
if (((x < 0) && (y > 3) || (z == 2)) cout << "OK?\n";
if (a != b && c > d && e < f && g == h) cout << "OK?\n";
int N = 0;
if (N = 0)
{ cout << "The conditional expression was TRUE\n";
}
else
{ cout << "The conditional expression was FALSE\n";
}
int i = 0;
if (0 != i)
4.8. PROBLEMS 71
(a) An example of the use of the if. If the condition is TRUE then one and only
one statement is executed.
A correct answer is: if (i < N) f = f*i;
(b) An example of the use of the if. If the condition is TRUE then exactly two
statements are executed.
(c) An example of the use of the if and the else if. If the if condition is TRUE
then exactly two statements are executed. If the else if condition is TRUE
then one and only one statement is executed.
(d) An example of the use of the if and two else ifs.
(e) An example of the use of the if, two else ifs and the else.
Feel free to use abbreviations, like URQ, for upper right quadrant.
% a.out
Enter two ints, representing x and y: 1 1
Upper right quadrant (URQ)
%
4.9. PROJECTS 73
4.9 Projects
1. Your first programming problem
You have to create an entire code that will compile correctly, accept inputs and provide
outputs and stops. As for coding style, follow Appendix A.
Your program will do the following:
The above set of instructions is really a coarse pseudocode for your program. Read the
instructions very carefully.
Here are some example uses of the program. Your program should work exactly the
same.
> a.out
Input the 1st integer: -1
Input must be non-negative. Try again!
> a.out
Input the 1st integer: 1
Input the 2nd integer: -1
Input must be non-negative. Try again!
> a.out
Input the 1st integer: 1
Input the 2nd integer: 1
74 CHAPTER 4. GETTING STARTED IN C++
> a.out
Input the 1st integer: 10
Input the 2nd integer: 0
The bigger number is 10, the smaller number is 0
The smaller number is 0, so no ratio is calculated, the quadrature sum is 100
> a.out
Input the 1st integer: 0
Input the 2nd integer: 10
The bigger number is 10, the smaller number is 0
The smaller number is 0, so no ratio is calculated, the quadrature sum is 100
> a.out
Input the 1st integer: 7
Input the 2nd integer: 4
The bigger number is 7, the smaller number is 4
The ratio is 1, the quadrature sum is 65
4 is not a perfect divisor of 7
> a.out
Input the 1st integer: 4
Input the 2nd integer: 7
The bigger number is 7, the smaller number is 4
The ratio is 1, the quadrature sum is 65
4 is not a perfect divisor of 7
> a.out
Input the 1st integer: 8
Input the 2nd integer: 2
The bigger number is 8, the smaller number is 2
The ratio is 4, the quadrature sum is 68
2 is a perfect divisor of 8
> a.out
Input the 1st integer: 2
Input the 2nd integer: 8
The bigger number is 8, the smaller number is 2
The ratio is 4, the quadrature sum is 68
2 is a perfect divisor of 8
4.9. PROJECTS 75
Write a program that will accept a positive int, the year to be tested, from a user.
If the user inputs a 0 or negative number, the program quits without doing anything.
Otherwise, it will print a message saying whether or not the year is a leap year. Here
is an example of how the program works.
unix-prompt> a.out
Input a number for the year (>= 1): -1
Sorry, your year must be greater than 1.
unix-prompt> a.out
Input a number for the year (>= 1): 2001
The year 2001 is not a leap year
unix-prompt> a.out
Input a number for the year (>= 1): 2004
The year 2004 is a leap year
unix-prompt> a.out
Input a number for the year (>= 1): 2100
The year 2100 is not a leap year
unix-prompt> a.out
Input a number for the year (>= 1): 2400
The year 2400 is a leap year
3. When in Rome...
The following table shows how Roman numerals are formed:
A Roman number is written in decades starting with the largest decade on the left
and then going to the right. For example, the number 1999 would be represented as
MCMXCIX. The largest number that can be represented by Roman numerals is 3999,
or MMMCMXCIX. Write a program that will accept a positive int, between 1 and
3999 inclusive. If the user inputs something outside this range, the program quits
without doing anything. Otherwise, it will print the conversion to Roman numerals.
Here is an example of how the program works.
unix-prompt> a.out
Input an integer between 1 and 3999 inclusive: 0
Sorry, your integer must be between 1 and 3999 inclusive.
unix-prompt> a.out
Input an integer between 1 and 3999 inclusive: 4000
Sorry, your integer must be between 1 and 3999 inclusive.
unix-prompt> a.out
Input an integer between 1 and 3999 inclusive: 1338
MCCCXXXVIII
unix-prompt> a.out
Input an integer between 1 and 3999 inclusive: 3888
MMMDCCCLXXXVIII
unix-prompt> a.out
Input an integer between 1 and 3999 inclusive: 52
LII
(a) Determines if the 5-bit bit pattern b4 b3 b2 b1 b0 represents an odd or even unsigned
integer.
(b) Determines if the bit pattern represents a negative or positive signed integer in
5-bit twos complement representation.
(c) Prints the unsigned integer representation.
(d) Prints the bit patterns bit complement b4 b3 b2 b1 b0 (1s become 0s and 0s become
1s).
(e) Prints the signed integer representation assuming 5-bit twos complement repre-
sentation.
unix-prompt> a.out
Bit b0: 0
Bit b1: 1
Bit b2: 0
Bit b3: 1
Bit b4: 0
5-bit bit pattern is: 0 1 0 1 0
Bit pattern represent an even unsigned integer
Bit pattern represent a positive signed integer
Unsigned integer representation is: 10
Complement 5-bit bit pattern is: 1 0 1 0 1
Signed integer representation is: 10
unix-prompt> a.out
Bit b0: 1
Bit b1: 1
Bit b2: 1
Bit b3: 1
Bit b4: 0
5-bit bit pattern is: 0 1 1 1 1
Bit pattern represent an odd unsigned integer
Bit pattern represent a positive signed integer
Unsigned integer representation is: 15
Complement 5-bit bit pattern is: 1 0 0 0 0
Signed integer representation is: 15
unix-prompt> a.out
Bit b0: 1
Bit b1: 1
Bit b2: 1
Bit b3: 0
Bit b4: 1
5-bit bit pattern is: 1 0 1 1 1
Bit pattern represent an odd unsigned integer
Bit pattern represent a negative signed integer
Unsigned integer representation is: 23
Complement 5-bit bit pattern is: 0 1 0 0 0
Signed integer representation is: -9
unix-prompt> a.out
Bit b0: 1
Bit b1: 0
78 CHAPTER 4. GETTING STARTED IN C++
Bit b2: 0
Bit b3: 0
Bit b4: 1
5-bit bit pattern is: 1 0 0 0 1
Bit pattern represent an odd unsigned integer
Bit pattern represent a negative signed integer
Unsigned integer representation is: 17
Complement 5-bit bit pattern is: 0 1 1 1 0
Signed integer representation is: -15
(a) multiply a 5-bit bit pattern by a 2-bit bit pattern, for example, 10101 11, or
(b) add two 5-bit bit patterns, for example, 10101 + 10011.
The user of your program will provide the bit patterns that are to be added or multi-
plied. Your code will output the 5-bit bit pattern that is the result of the multiplication
or addition.
Examples of use:
Here is an example of running the code:
> a.out
10101
x 11
------
10101
+01010
------
11111
>
> a.out
10101
+10011
------
01000
>
unix-prompt> a.out
Input a dollar amount between 0.00 and 19.99 inclusive: 19.94
Change of $19.94 is best given as:
One $10 bill
One $5 bill
Four $1 bills
Three quarters
One dime
One nickel
Four pennies
unix-prompt> a.out
Input a dollar amount between 0.00 and 19.99 inclusive: 16.26
Change of $16.26 is best given as:
One $10 bill
One $5 bill
One $1 bill
One quarter
One penny
unix-prompt>
unix-prompt> a.out
Input a positive int between 0 and 127 inclusive: 126
4.9. PROJECTS 81
unix-prompt>
Hint: Depending on your algorithm, you may find it useful to use the escape sequence
\b which causes the cursor to move backwards one space.
unix-prompt> a.out
Input the base to convert to between 2 <= b <= 9: 7
Input any positive unsigned int: 126
Decimal 126 converted to base 7 is 240
unix-prompt>
82 CHAPTER 4. GETTING STARTED IN C++
Chapter 5
Loops
Loops are the third and final programming element we need to write any algorithm. The
C++ language provides three easy ways to do this, the while, do/while and for loops.
83
84 CHAPTER 5. LOOPS
It puts your computer in a state known formally as hung, as in, Jeepers, I think
my computer is hung. It is NOT a compliment! Hung computers are put out of their
misery by a variety of desperate measures, increasing in severity. At the very worst,
the power has to be shut down, a really nasty, last resort for a hung computer.
?
F
T
STATEMENT BODY
//File: gauss.cpp
#include <iostream>
int main(void)
{ cout << "Input N: ";
int N;
cin >> N;
int i = 0, Sum = 0;
while (i < N)
{ i = i + 1;
5.1. THE WHILE LOOP 85
Sum = Sum + i;
}
cout <<
"Sum of " << N << " digits is " << Sum
<< "...according to Gauss: " << N*(N+1)/2 << "\n";
return(0);
}
//File: gaussAgain.cpp
#include <iostream>
int main(void)
{ cout << "Input N: ";
int N;
cin >> N;
int i = 0, Sum = 0;
while (i = i + 1 <= N) Sum = Sum + i; //NO, NO, NO!
cout <<
"Sum of " << N << " digits is " << Sum
<< "...according to Gauss: " << N*(N+1)/2 << "\n";
return(0);
}
This is dangerous because if you forgot the parentheses around the i = i + 1 part of the
conditional, you would generate an infinite loop! Dont believe me? Try it! Um, wait, this
is a forever loop! OK, try it, but <CNTL>-C out of it after a few seconds.
The point istry to make your coding as easy to interpret as possible. Dont be too clever.
Dont save space just for the purpose of saving space at the expense of clarity. In the old days
of computing, memory and disk space were very expensive and precious. Programmers prided
themselves at making things very compact. Those days are, happily, long gone. However,
there still are people who do this. Maybe they think that an electron is as expensive as a
Higgs boson1 .
1
Electrons are essentially free. There are countless numbers of them in everyday things, like water. The
86 CHAPTER 5. LOOPS
Higgs boson is very expensive. Physicists are spending billions to find it. It has not been found yet, but
almost! The first person to find it will win the Nobel Prize for physics.
5.2. THE DO/WHILE LOOP 87
STATEMENT BODY
?
T
F
The only thing that really distinguishes a do/while loop from a while loop is that the
do/while loop evaluates the conditional at the end of the STATEMENT BODY and the while
loop evaluates it at the beginning. while loops are often used when incrementing a counter
and using (and usually updating) the counter within the statement body. do/while loops
are useful if you always want to process the STATEMENT BODY at least once. Because of this,
loops that accept input from the keyboard (or a file) make good use of the do/while loop
especially when the input is terminated using a sentinel.
Here is an example of sentinel controlled output for calculating the average of student grades.
The sentinel for stopping is when the input for a grade is less than zero. Even the cruelest
professor does not hand out a negative grades (even though it is legal)! So, this is a good
sentinel to use for this application.
//File: grades.cpp
#include <iostream>
int main(void)
{ int nStudents = 0, grade, sumGrades = 0;
do
{ cout << "Input a grade: ";
cin >> grade;
if (0 < nStudents)
cout << nStudents
<< " grades were read in. "
<< "The class average is: "
<< sumGrades/nStudents
<< "\n";
return(0);
}
Note that the above calculates the average as sumGrades/nStudents, the result of an integer
division. This may not be completely fair as an average of, say, 79.9 should not really be
reported as 79.
The way to fix this is to make the following changes:
#include <iomanip>
The code in its entirety can be found in the lectures area on the web. It is called grades1.cpp.
There are two new features in the cout statement. One is the introduction to the unary
cast operator static_cast<float>(expression) which converts sumGrades temporarily
(and internally) to a float and the resulting calculation takes place as if it were a divide using
floats alone. It is not necessary to make the same conversion for nStudents. The division
of a float by an integer or an integer by a float always results in a floating point calculation
as the integer participating is promoted to a float.
The general form of the cast operator is
to change expression to the type type_name. So, floats can be changed to ints and vice-
versa. It is possible to change among other types of variables that we will encounter later.
The other new feature is the use of a field width and precision to modify the output of
the float. The function setw(m) sets aside m spaces to print. The function setprecision(n)
prints n significant digits. These functions are defined in the iomanip (I/O stream manipula-
tor) library file. Hence, we had to include this file, else the compiler would have complained.
Note how these functions are employed. setprecision() only has to be set once. The
stream handlers remember it. However, setw() has to be set for every item!
There is another commonly used stream manipulator called fixed. We will not use it much.
It is described in Chapter 2 of Horstman.
If the STATEMENT BODY consists of one and only one statement, then the surrounding
{}s are optional. (It can help with clarity of programming to keep them, however.
Their use is highly recommended.)
90 CHAPTER 5. LOOPS
Processing control passes to the statement immediately following the for construct
after condition tested by the logical expression fails.
for loops (in fact, any repetition loop) can be nested within each other.
The logical expression is intended to provide the condition for which the execution
of the for loop terminates. This logical expression can mix arithmetic and logical
operators to make for compact coding. (This is not really recommended for novice
programmers and often makes code hard to read.)
The STATEMENT BODY will not be executed if the logical expression is false initially.
expression 1 is intended to initialize the loop counter (or index). Its use is optional.
However, in this case the initialization of any counters (should they be used) should
be done beforehand.
The use of the logical expression is also optional. If not provided, the STATEMENT
BODY is always entered. Another way of exiting the loop has to be provided otherwise
the loop is infinite.
The two ;s in the definition of the for loop are NOT optional. Leaving one or both
out will result in a compilation error.
EXPRESSION 1
?
F
T
STATEMENT BODY
EXPRESSION 2
//File: blastOff.cpp
#include <iostream>
int main(void)
{ cout << "Estimate number of counter loops/second: ";
int loopsPerSecond;
cin >> loopsPerSecond;
int screenHeight;
cin >> screenHeight;
"Draw" a rocket
cout << " /\\\n"
<< " ||\n"
<< " ||\n"
<< " ||\n"
<< " ||\n"
<< "/||\\\n";
return(0);
}
94 CHAPTER 5. LOOPS
5.4 Problems
1. Flowcharts revisited
Draw the flowchart representation (using lines, arrows, rectangles, diamond-shapes,
and words) for the following looping constructs:
2. Loop tests
int j = 1;
do
{ j = -2*j + 1;
}while(j != 0);
(f) How many times is the following loop body executed?
for(int i = 0; i < 10; i = i + 2)
{ cout << "i = " << i << "\n";
}
(a) int N = 0;
if (N = 0)
cout << "The conditional expression was TRUE\n";
else
cout << "The conditional expression was FALSE\n";
(b) int f;
for(f = 0; f <= 10; f = f + 2)
cout << f%10;
cout << "\n";
(c) int i = 0, Sum = 0, N = 3;
do
{ i = i + 1;
Sum = Sum + i;
}while(i <= N);
cout << "Sum = " << Sum << "\n";
(d) int i = 0;
if (0 != i)
cout << "Statement 1\n";
cout << "Statement 2\n";
cout << "Statement 3\n";
(e) int j = 0;
if (0 < j);
{ j = j + 1;
}
cout << "j = " << j << "\n";
(f) int i = 2, j = -2;
while (j <= i)
96 CHAPTER 5. LOOPS
{ if (j < 0)
cout << "i is " << i << ".";
cout << " j is " << j << ".\n";
i = i - 1;
j = j + 1;
}
4. Loop drills
(a) Convert the following code containing a do/while loop to a code containing a
while loop in such a way that the execution of the code is identical.
int j = 0;
do
{ j = j + 1;
cout << j << "\n";
int main(void)
{ int x = 1;
for (int i = 1; i <= 10 ; i = i + 1)
{ x = x*2;
cout << x << " ";
}
cout << endl;
return 0;
}
5.4. PROBLEMS 97
What does the above code print to the screen when you run it?
Draw the flow chart for the for loop in the above program.
(d) Consider the following code:
#include <iostream>
int main(void)
{ int i = 5;
do
{ i = i - 1;
cout << i << " ";
}while(i);
cout << endl;
return 0;
}
What does the above code print to the screen when you run it?
Draw the flow chart for the do{}while(); loop in the above program.
(e) Consider the following code:
#include <iostream>
int main(void)
{ int i = 13;
while(i%2)
{ i = i/3;
cout << i << " ";
}
cout << endl;
return 0;
}
What does the above code print to the screen when you run it?
Draw the flow chart for the while(){}; loop in the above program.
(f) Consider the following code:
#include <iostream>
int main(void)
{ for (int i = 1; i <= 2; i = i + 1)
for (int j = 1; j <= 3; j = j + 1)
cout << i << "," << j << endl;
return 0;
}
What does the above code print to the screen when you run it?
Draw the flow chart for the nested for loops in the above program.
#include <iostream>
#include <cmath>
using namespace std;
int main(void)
{ float x;
cout << "Input x (must be positive): ";
cin >> x;
int i = 0;
const int NMax = 1000;
const float SMALL = 0.0001;
float xPower = 1.0, lastTerm, Sum = 0.0;
do
{ i = i + 1;
xPower = x*xPower;
lastTerm = xPower/i;
Sum = Sum + lastTerm;
}while (i < NMax && lastTerm > SMALL);
if (i == NMax)
cout << "Series did not converge\n";
else
{
cout << "i = " << i << "\n"
<< "x = " << x << "\n"
<< "lastTerm = " << lastTerm << "\n"
<< "Sum = " << Sum << "\n";
}
5.4. PROBLEMS 99
return 0;
}
(a) What series is being summed by this code? Sum = x + (you provide the rest)
(b) If the user inputs -1.0 for x, what will be printed out by this code?
(c) If the user inputs 0.0 for x, what will be printed out by this code?
(d) If the user inputs 1.0 for x, what will be printed out by this code?
(e) If the user inputs 0.0001 for x, what will be printed out by this code?
(f) If the user inputs 0.001 for x, what will be printed out by this code?
(g) If the user inputs 0.01 for x, what will be printed out by this code?
(h) If the user inputs 0.1 for x, what will be value of i that is printed out by this
code? (A hand calculator may help.)
#include <iostream>
#include <cmath>
using namespace std;
int main(void)
{ float x;
cout << "Enter x: ";
cin >> x;
int n = 0;
float lastTerm;
const float EPSILON = 0.001;
float sign = 1;
float denominator = 1;
float total = 1;
while(n <= 1 || lastTerm > EPSILON)
{ n = n + 1;
if (n/2*2 == n)
{ denominator = denominator*n*(n - 1);
lastTerm = pow(x,n)/denominator;
sign = -sign;
total = total + sign*lastTerm;
cout << "Term " << n << " is " << lastTerm << "\n";
100 CHAPTER 5. LOOPS
}
}
return 0;
}
(a) Prediction part: If you compiled and ran this program, exactly what would the
output look like?
#include <iostream>
int main(void)
{ const int maxTerms = 8;
const int x = 2;
int sign = 1;
int term = 1;
for (int i = 1; i <= maxTerms; i = i + 1)
{ sign = -sign;
term = term*x;
if (0 == i%2 || 2 <= i && 4 >= i)
{ cout << i << ":";
if (0 > sign) cout << " - ";
else cout << " + ";
cout << term << endl;
}
}
return 0;
}
5.4. PROBLEMS 101
(b) Conversion part: Convert the program in the first part of this question to use
a do-while loop rather than a for loop. Write your solution in the space below.
(a) Prediction part: If you compiled and ran this program, exactly what would the
output look like?
#include <iostream>
int main(void)
{ const int maxTerms = 8;
const int x = 2;
int term = 1;
int sum = 1;
cout << "Sum = 1";
for (int i = 1; i <= maxTerms; i = i + 1)
{ term = -term*x;
if (0 != i%3 && 0 != i%4 )
{ if (0 > term) cout << " - " << -term;
else cout << " + " << term;
sum = sum + term;
}
}
cout << " = " << sum << "\n";
return 0;
}
(b) Conversion part: Convert the program in the first part of this question to use
a while loop rather than a for loop. Write your solution in the space below.
S = 1 x2 + x4 x6 + x8 x10
The code has errors that the compiler detects as indicated in the comment lines. Fix
them. The code also has conceptual errors in some lines, also indicated by comments.
Conceptual errors are those that compile without error but do not provide correct
answers upon execution. Fix these as well.
102 CHAPTER 5. LOOPS
#include <iostream>
using namespace std;
int main(void)
{ float x;
cout << "Input x: ";
cin >> x;
return 0;
}
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;
int main(void)
{ srand(time(NULL));
for(int nCards = 1; nCards <= 5; nCards = nCards + 1)
{ int rank = rand()%13 + 1;
// You fill in the rest
.
.
.
.
} // End of the for loop over the 5 cards
return 0;
} // End of the main routine
104 CHAPTER 5. LOOPS
program that will accept a positive float for the starting balance and output how much
money you will have at the end of each year. The program stops when your money
has at least doubled.
Heres an example of how it works:
% a.out
Input the starting balance: 1000
Reads in an int representing the first month the money is put in the bank,
Reads in an int representing the number of months the money is in the bank,
Reads in a float for the amount of money deposited,
Loops over the number of months that the money is in the bank, and,
If the current month has an r, multiplies the total by 1.01,
And finally, prints out the final amount of money.
calculates the month, given a starting month and a number of months elapsed. For
example, if you start in January (Month 1), 13 months later it is February (Month 2).
(a) Prompt the user for a positive odd integer within a do-while construct. If the
integer is 0, negative or even, prompt the user again. The algorithm goes to the
next step when an odd positive integer is received. Call this odd integer N.
(b) Output an inverted triangle of asterisks that looks like the following example.
The first row has N *s. Each following row has two *s less than the one above it
and is centered with respect to the row above.
red% a.out
Input an odd positive int: -1
Input an odd positive int: 0
Input an odd positive int: 2
Input an odd positive int: 11
***********
*********
*******
*****
***
*
red%
****************************************
*********** *
* ********** *
* ********** *
* ********** *
* ********** *
* ********** *
* ********** *
* ********** *
* ********** *
* ********** *
* ********** *
* ********** *
* ********** *
* ********** *
* ********** *
* ********** *
108 CHAPTER 5. LOOPS
* ********** *
* ********** *
* ********** *
* ********** *
* ********** *
* ********** *
* ********** *
* ********** *
* ********** *
* ********** *
* ********** *
* ********** *
* ***********
* **********
* *********
* ********
* *******
* ******
* *****
* ****
* ***
* **
****************************************
You ...
Height of box: 30
Width of box: 30
* * * * * * * * * * * * * * *
** ** ** ** ** ** ** ** ** **
*** *** *** *** *** *** *** **
**** **** **** **** **** ****
***** ***** ***** ***** *****
****** ****** ****** ****** **
******* ******* ******* ******
******** ******** ******** ***
********* ********* *********
********** ********** ********
*********** *********** ******
************ ************ ****
************* ************* **
************** **************
*************** **************
**************** *************
***************** ************
****************** ***********
******************* **********
******************** *********
********************* ********
********************** *******
*********************** ******
************************ *****
************************* ****
************************** ***
*************************** **
**************************** *
*****************************
You must only use cout statements that have only single character, for example,
cout << "*";. Something like cout << "**"; or cout << " *"; is not permit-
ted. Spaces are counted as a character.
5.5 Projects
1. Something loopy to do
Write a C++ program that converts any unsigned integer to any base between 2 and
9.
Heres an example of how it should work for an input of 126:
unix-prompt> a.out
Input the base to convert to between 2 <= b <= 9: 7
Input any positive unsigned int: 126
Decimal 126 converted to base 7 is 240
unix-prompt>
(a) START: Declare N = 0 (Counter for the number of steps), xi , yi (New coordi-
nates), x0 = 0, y0 = 0 (Current coordinates), s (Distance of a single step) and
t = 0 (Total distance).
(b) Start of the input/stepping loop.
i. Read in the the new coordinates: xi and yi.
ii. Test to see if xi and yi are valid input. If they are not, go back to (b-i.),
otherwise continue on to the next step (b-iii.).
112 CHAPTER 5. LOOPS
iii. Test to see if xi and yi are identical to x0 and y0 . If they are not you will
continue with step (b-iv.) Otherwise you will want to transfer control to the
the first statement following the input/stepping loop, step (c).
iv. Increment the step counter N.
q
v. Calculate the distance of the step s = (xi x0 )2 + (yi y0 )2 .
vi. Accumulate s in t, the total distance.
vii. Important! Update the current position x0 = xi , y0 = yi .
viii. Try to take another step, that is return control to the top of the input/stepping
loop, step (b-i.).
(c) Report the total distance traveled.
(d) Report the total number of steps.
(e) Report the average distance traveled per step. Important: make sure that the
case of zero steps and zero distance traveled does not cause problems.
(f) END:
5.5. PROJECTS 113
int main(void)
{ cout << "Input N: "; int N; cin >> N;
if (0 > N)
cout << "N < 0. Stopping.\n";
else if (0 == N)
cout << "0! = 1\n";
else
{ int factorial = 1;
for (int i = 1 ; i <= N; i = i +1)
factorial = factorial*i;
cout << N << "! = " << factorial << "\n";
}
return 0;
}
This program computes the factorial of the integer N, input by the user. The
factorial of N, represented by the mathematical symbol N!, is calculated by:
N! = N (N 1) (N 2) (N 3) 3 2 1
mathematically, or you can run your program for different values of N until you
detect that something is wrong. How do you know that something has gone
wrong? Turn in a description of how you found the answer.
(c) Calculating the exponential of a number
The exponential function, called ex is one of the most common functions in all of
mathematics. One way of calculating it is to use the following:
1 x x2 x3 x4 x5 xn
x
e = + + + + + +
0! 1! 2! 3! 4! 5! n!
an infinite series, one that never stops. Mathematically, the above expression for
ex is exact for any x from minus infinity to plus infinity. However, to get an
accurate calculation from a computer requires some work. Here is what you have
to do:
i. Write a C++ program to compute ex . Your program should try to compute
it by summing the finite series
1 x x2 x3 x4 x5 xN
ex = + + + + + +
0! 1! 2! 3! 4! 5! N!
where N is some integer that you, the programmer, will set. Be careful
that you do not set N too high, otherwise, as indicated in the previous two
problems, your answer may not make sense. N should also be great enough
so that your answer is as accurate as it can be. Turn in your code.
ii. Discuss over what range of x you expect your program to provide a reasonably
accurate answer. Turn in your discussion in such a way that pleases your Lab
Instructor.
You can check your results with a calculator. Else, if you read ahead, you can
check your program using the C++ math function exp(x).
5.5. PROJECTS 115
Hint 3: If you are using Hint 2 as a way of checking your program (please do!) and
you find that it takes a very, very long time to get your program to complete its task,
stop a moment and think! Think about how many potential divisors you have to test
to see if a number is prime or not. It should not take more than about a minute or
so to find all the primes between 4 and one million, depending on what machine you
are using. On a 700 MHz PIII machine a solution takes about 70 seconds if it outputs
every number it finds to the screen and only about 10 seconds if it outputs only the
number of primes found. To be sure, there are even faster ways of doing it!
Finding prime numbers is an exercise that has intrigued mathematicians for centuries.
As soon as computers were invented, this was one of the early problems that mathemati-
cians programmed them for. We know that integers have only 32-bit representations.
This is just food for thought, not part of the question: How you would find out if a
number bigger than 232 is prime? Now thats a tough computer problem. Here is an
example of output from correct solution:
Looking for all the prime numbers between 4 and 1000000 inclusive
5 is prime
7 is prime
11 is prime
13 is prime
17 is prime
19 is prime
23 is prime
29 is prime
31 is prime
37 is prime
41 is prime
43 is prime
47 is prime
53 is prime
59 is prime
61 is prime
67 is prime
71 is prime
73 is prime
79 is prime
83 is prime
89 is prime
97 is prime
.
.
.
999953 is prime
999959 is prime
999961 is prime
999979 is prime
999983 is prime
There were 78496 prime numbers between 4 and 1000000 inclusive
5.5. PROJECTS 117
5. Wheres Waldo?
It is a little known fact that Waldo Schtinklebaum, the character of the infamous
Wheres Waldo? game was a student here at the University Michigan. He started
off his career in Civil Engineering. He was notorious for 1) being a lousy dresser, 2)
having no sense of direction (why he was always getting lost), 3) and being indecisive.
In fact, after partying all night at the Frats, Waldo would often lose his way back
to his dorm. Hed leave the party, forget which way his dorm was, take a step in a
random direction, change his mind and his direction and take another step. This is not
a bad approach to getting where you want to go, except that it can take a very long
time to reach your destination. Waldo sometimes ended up walking around randomly
until the morning when someone would take pity on him and lead him back home. In
fact, Waldos meanderings led to his second career. Shortly after graduation, Waldo
participated in the infamous Spring running event that takes place in the late evening
on the last day of Winter term. On this day, Waldo changed his manner of dress
permanently. Despite his motivation to run in the correct direction, Waldo ended up
in the Kresge Eye Center were his vision was corrected and he donned the hospital
greens of a medical doctor. Waldo is now an optometrist working in Livonia under an
assumed name. His specialty is treating children who have gone cross-eyed staring at
the puzzles that bears his former name.
Your project is to write a program that imitates Waldos after-party mission to get
home. A pseudocode description of the solution is given below.
Pseudocode for Waldos mission
Waldo starts his journey at location (x, y) = (0, 0), the front door of the Frat
house, the center of the universe that Waldo is in. Waldos universe is a 2-
dimensional plane that measures 2020, that is 10 x 10 and 10 y 10.
Waldos home is a 2 2 square in the upper right hand corner, 8 x 10 and
8 y 10.
Declare a variable called stillWalking and give it an initial value of 1 (true),
which means that Waldo is still trying to find his way home on foot.
Declare another variable called atHome and give it an initial value of 0 (false)
which means that Waldo has not yet found his way home.
Declare another variable called stepsToTry and give it an initial fixed value of
1000. Waldo hopes to get home before 1000 steps. If he doesnt, you will either
tell him to keep going and try another 1000 steps, or to give up and sleep on the
nearest park bench.
WHILE (stillWalking)
FOR-LOOP until 1000 steps are taken and while Waldo has not yet reached
home.
DO (Loop for choosing the direction of the step)
118 CHAPTER 5. LOOPS
#include <cstdlib>
in the preprocessor area for the code. Then, an expression of the form:
rand()
will produce a random int between 0 and RAND MAX inclusive, where RAND MAX is a big
positive number defined in cstdlib. This random int must be converted to a random
double that lies between 0 and 2. This can be done via the following statement:
#include <cmath>
dx = cos(angle);
dy = sin(angle);
where dx and dy are doubles. This is one of Waldos steps. You should use exactly
this order of displacement statements in your solution.
Example use of the program
red% a.out
Will Waldo make it home? Press <RETURN> to continue.
#include <ctime>
Then, in your code before your first use of rand(), put in the following expression:
srand(time(NULL));
Thats how I generated the different solutions that are shown in graphical form on the
next page. The expression time(NULL) gives the number of seconds since the start of
the epoch, January 1, 1970, 12:00am GMT. This is considered to be the start of the
modern computer age.
Note that you can also seed the random number generator rand() using the following
statement:
120 CHAPTER 5. LOOPS
srand(someInt);
where someInt is an int that you can choose. If you choose the same someInt every
time, the game will be the same. Different someInts result in different games. Try it!
Some things to think about (optional)
These are some things to think about. Dont hand answers to these to your GSIs.
However, feel free to speak to them or me (the Prof) about it.
Wandering Waldo
First example
Waldo Home
gets
inspired!
Wandering Waldo
Second example
122 CHAPTER 5. LOOPS
Chapter 6
Early AbstractionFunctions
//File: alKashi.cpp
#include <iostream>
int main(void)
{ cout << "A calculation of X (float) to the power of N (int) \n";
123
124 CHAPTER 6. EARLY ABSTRACTIONFUNCTIONS
if (0 > N)
{ //This "trick" allows us to calculate for negative powers!
n = -N;
x = 1/X;
}
cout << X << " to the power " << N << " = " << result << "\n";
return(0);
}
delimit a code blockthis one associated with the Al-Kashi algorithm. Variables can be
defined within a code block. Those that are defined within them (in this example, float x
and int n) are not known (or defined) outside of the the block. If you tried to do something
with x or n outside of their block, you would get a compilation error, complaining that these
variables were not defined. At least, that will be our understanding of code blocks until we
get to the section called scope rules a little later in the course. We have actually seen
code blocks before. The main routine has one, as well as the if/else if/else construct,
the while and do/while constructs as well as the for loop.
6.1. MOTIVATION FOR FUNCTIONS 125
Now, suppose that we did not know about the al-Kashi algorithm and coded the algorithm in
a more straightforward way (This code is called dumbPower.cpp on the lecture distribution
area on the course website.):
//File: dumbPower.cpp
#include <iostream>
int main(void)
{ cout << "A calculation of X (float) to the power of N (int) \n";
if (0 > N)
{ n = -N;
x = 1/X;
}
result = 1; // Initial value
cout << X << " to the power " << N << " = " << result << "\n";
return(0);
}
In these two examples, we note that there is a lot of repetition in the code outside of the
scope block. Repetitious coding is BAD! It means that someone has wasted a lot of time!
126 CHAPTER 6. EARLY ABSTRACTIONFUNCTIONS
Indeed, as far as the main routine is concerned, it does not really care about the contents of
the code block! All it really wants is the answer. It can think of the algorithm to compute
the power in a very abstract way. All main really needs to do is to give the scope block the
variables X and N.
What we really, REALLY want is a routine that is independent of the specific calculational
technique that is used to obtain X N . In fact there is. There is a function in the C++
standard math library that does this. It is called pow. If we use this information we can
write a much more compact code (This code is called power0.cpp on the lecture distribution
area on the course website.):
//File: power0.cpp
#include <iostream>
#include <cmath>
int main(void)
{ cout << "A calculation of X (float) to the power of N (int) \n";
result = pow(X,N);
cout << X << " to the power " << N << " = " << result << "\n";
return(0);
}
#include <cmath>
result = pow(X,N);
6.1. MOTIVATION FOR FUNCTIONS 127
This is a much more abstract and powerful implementation of the previous two examples.
It allows the main routine to be concerned with only the input and output of the various
parameters, X, N, and the answer. The main routine in this case is much more general.
Let us pretend that we are now in the infancy of the C++-language, and that the pow function
does not exist. However, we require this functionality repeatedly in our applications. But,
we do know about al-Kashis algorithm. Wanting to be efficient, we would code the al-Kashi
algorithm into a C++-function and employ it as follows (This code is called power1.cpp on
the classcodes distribution area):
//File: power1.cpp
#include <iostream>
if (0 > n)
{ n = -n;
x = 1/x;
}
result = 1;
while(1 <= n)
{ if (0 == n % 2)
{ n = n/2;
x = x*x;
}
else
{ n = n - 1;
result = result*x;
}
}
return result;
}
int main(void)
{ cout << "A calculation of X (float) to the power of N (int) \n";
128 CHAPTER 6. EARLY ABSTRACTIONFUNCTIONS
result = pow(X,N);
cout << X << " to the power " << N << " = " << result << "\n";
return(0);
}
Now we note a few important things. There are a lot of things to remember about functions
and we are only going to scratch the surface.
In our use of functions, the function definitions and the main routine go in one file.
(They can be put into different files but it becomes more complicated.)
The function definitions go at the top of the file, after the pre-processor directives but
before the definition of the main routine. (They can be put after the main routine but
it becomes more complicated.)
The functions definitions should go before they are used in any other function, including
main. (Again, we can use another ordering, but it becomes more complicated.)
Functions, the way we have used them so far, can return only one thing via the state-
ment
return expression.
The expression in the return line must evaluate to a data type that is specified in
the definition of the function, in this example, float pow()...
The parameters in the function definition, in this example, (float x, int n), must
be declared.
The variables in the function call, in this example, X,N from mains function call
result = pow(X,N);
are not changed by the function. (There is another way to call functions where the
parameters can change. This will be taught later.)
6.2. USER-DEFINED FUNCTIONS 129
Once the function returns to its calling routine, main in this case, the variables in
the functions parameter list and any other variables that it declares, are lost. The
only thing that main has is the return value. (To be absolutely truthful, there are
ways that the calling routine can look at the memory where the function stored things
temporarily, but...its complicated! Moreover, it is almost never done.)
Functions can call other functions.
main is just another function.
If a function does not return anything, its type is void. Example,
void returnNothingFunction(void){}
If a function has no parameters, put void where the parameter list goes, as in the
above example.
Finally, functions are really, really, REALLY important. So it is important to un-
derstand them and use them well. We will spend a lot of effort in this course with
functions.
The function prototype: For small applications, where all the source code is found in
one file, the function prototype is usually written in the pre-processor area, the area
before any function definition (see below). In small applications, where all the source
code is found in one file, the function prototype can be omitted if the function defini-
tion is located in the file before any function call (see below) is made to it. For large
applications, or applications that have more than one source file, function prototypes
are usually gathered into an include file, named, for example, myIncludes.h and ac-
cessed via an include statement #include <myIncludes.h> placed in the preprocessor
area.
The function definition: For small applications, where all the source code is found in
one file, the function definition is written after the function prototype and outside
of the main routine. For large applications, or applications that have more than one
source file, it is conventional to have one function definition per source file.
130 CHAPTER 6. EARLY ABSTRACTIONFUNCTIONS
The function call: The call to the function can be inside of main or another function.
In fact, a function can even call itself. This is called recursion and is discussed in a
later chapter.
Understanding the syntax of these three things is crucial to the successful use of functions.
The general use of a user-defined function is as follows:
/* Opening comments */
.
.
.
// Start of pre-processor directives
.
.
.
// function prototype (if required)
(type) myFunction(variable type list separated by ,s);
.
.
.
// end of pre-processor directives
.
.
.
/* function definition */
(type) myFunction(variable type list and variables separated by ,s)
{
.
.
.
/* Function body with declarations and
executable statements
*/
.
.
.
}
.
.
.
int main (void)
{ // Start of main routine
6.2. USER-DEFINED FUNCTIONS 131
.
.
.
// function usage
...myFunction(list of values separated by ,s)...;
.
.
.
} // End of main routine
The function prototype is the declaration of a function. It specifies what the function
is expected to provide (return value, see below), what is in the parameter list (inside
the parentheses) and its identifier (name). You do not need a function prototype if
all your source code is located in one file and if the first time the compiler encounters
your function within a source code file is the function definition itself. The compiler
will form its own prototype from the definition! This is why we can get away with
not using prototypes in most cases when everything is in the same file, the function
definitions are in the proper order and main comes last. There are exceptions to this
rule but we will probably not encounter them in this course. If the compiler encounters
the function for the first time in the function call, it will form its own prototype and
assume that the return type is an int and can potentially mess up on the argument
list as well. Avoid this situation at all costs!
The (type) in the function prototype and function definition inform the compiler
that the function called myFunction will return a variable of a certain type. (type)
could be float, e.g.
float myFunction();
Other possibilities for (type) could be int or any other variable type in C++ (that
have not been discussed yet in this course).
The other possibility for (type) is void. void means that the function will not return
a value. (It will perform a function on some data but not return any kind of value.)
(type) in the function prototype and function definition must agree, else there
will be a syntax error.
132 CHAPTER 6. EARLY ABSTRACTIONFUNCTIONS
Forgetting to return a value when (type) indicates that one should be returned results
in unpredictable behavior.
Note that
main ()
{ .
.
.
}
because functions are assumed to be (type) int unless we state otherwise. main is a
special function in C++ that the operating system knows is the place where to start
processing. Only main has this special status. I always (type) every function that I
define and you should do the same.
The rules for naming a function, e.g. myFunction, are the same rules as for variables,
i.e. the normal identifier naming rules ( 31 alphanumeric characters and the under-
score character and NOT starting with a number.)
The argument list in the function prototype is a comma separated list of variable types,
e.g.
which indicates myFunction will be called and defined with a float, an int, and a
float in that order. Heres another example:
A variable type is required for any non-int. Therefore, declaring a variable position as
an int is optional. However, it is recommended that you declare the variable type for
all members in the parameter list.
6.2. USER-DEFINED FUNCTIONS 133
The parameter list in the function definition follows the same rules except that the
variables must be named. e.g.
The function call (within the body of the main routine or within the body of another
function) as shown here:
transmits the values of the variables in the parameter list to the function. This is
termed call by value. There is another way of doing this termed call by reference
which we will discuss later.
The variables defined in the function definition (as well as any other variables that the
function defines) are internal to that function, even if the name (identifier) is identical
to a name elsewhere in the program.
Functions must all be defined in a separate code segment. You can not define a function
within another function.
Function prototypes outside of the body of any function apply to all function calls in
that source file.
Function prototypes inside the body of any function apply only to the associated calls
within that function.
1. by running into its closing brace } (this will work only for void functions)
2. running into the following statement anywhere in the function body
return;
134 CHAPTER 6. EARLY ABSTRACTIONFUNCTIONS
Prof to Team: Team: We will write a code to solve the quadratic equation! Well patent
it and Ill get rich!
Team to Prof: Yeah, right!
Prof to Bill: Bill, I want you to write a bool function called realQuadraticRoots that
will return an integer, and accept the three floats a, b and c in that order. If there are
no real roots your function has to return the value false. If there are, it has to return
the value true.
Bill to Prof: Um, Prof, whats a bool??
Prof to Bill: Its a variable type that can only have two values, true or false. It is
declared and assigned value as follows:
Eugene to Prof: You probably want me to write a function called something like
twoQuadraticRoots that will return no value, and accept the three floats a, b and
c in that order and print a statement telling you what the two roots are. You will only
call your routine if Janes routine tells you that there are two real roots. Right?
Prof to Eugene: Eugene, stop interrupting! I want you to write a function called
twoQuadraticRoots that will return no value, and accept the three floats a, b and c
in that order and print a statement telling me what the two roots are. I will only call
your routine if Janes routine tells me that there are two real roots.
Prof to Team: Stop kvetching already! Heres the main routine with function stubs.
You guys fill in the blanks. My code compiles so its absolutely perfect.
//File: quadraticRootsStubs.cpp
#include <iostream>
//Do I need anything else, fellow programmers?
//Function stubs
bool realQuadraticRoots(float a, float b, float c)
{
}
int numberQuadraticRoots(float a,float b,float c)
{
}
void twoQuadraticRoots(float A, float B, float C)
{
}
int main(void)
{ cout << "a, b, c: ";
float a, b, c;
136 CHAPTER 6. EARLY ABSTRACTIONFUNCTIONS
return 0;
}
Heres Janes code. Her job was made easier by Bills code letting her know that there is at
least one solution.
Eugene, who thinks hes a genius and a super-geek, likes to do things his own way. He
likes to store all the values his function receives in uppercase variables. Eugene has his own
coding style. Eugene also thinks he is smarter than the compiler and so he played with the
quadratic equation to put it into a form that he thinks will execute faster. (You can verify
for yourselves that what Eugene did was correct mathematically.)
Some comments are in order for the Profs code. It is incomplete. It does not do anything
when there is only one solution. His code needs a little refinement before it can be considered
complete. And, he has to decide what to do if all the constants are zero.
As a postscript to this story, function stubs are a good alternative to function prototypes
for small projects. Note that the Profs stub code will compile so that he can at least check
his programming. However, for larger projects, prototypes are the way to go.
138 CHAPTER 6. EARLY ABSTRACTIONFUNCTIONS
return returnValue;
This is unsatisfactory and restrictive if we need to return more than one value. An alternate
way of calling functions, a way that can return more than one thing is called call by reference.
This discussion must start, however, with a discussion of the addresses of variables, that is,
where they are stored in a computers (virtual) memory.
We introduce the unary operator called the address operator, &. To see its usage, consider
the following program :
//File: addressLocal.cpp
#include <iostream>
int main(void)
{ float x = 1.0f; // Declare and initialize a float
double y = 3.0; // Declare and initialize a double
int z = 2; // Declare and initialize an int
cout <<
"xs value: " << x << " xs address: " << &x << "\n"
"ys value: " << y << " ys address: " << &y << "\n"
"zs value: " << z << " zs address: " << &z << "\n";
return 0;
}
New stuff:
The address operator & applied to a variable, for example, &y should be read as the
address of the double y.
6.4. CALL BY VALUE, CALL BY REFERENCE, REFERENCE PARAMETERS 139
When cout prints an address, it prints it out as 0x... which is the hexadecimal (hex)
representation. The leading 0x is there just to tell you that what follows is in hex.
Note the the address stack grows from a large address towards smaller addresses.
Note the the operating system (a Linux installation in this case) puts the first variable it
encounters (in this case a 32-bit float) at address 0xbffff734. (This address, once con-
verted to an integer number, is something in excess of 3 billion.) This is the address in bytes,
one byte being 8 bits. A 32-bit machine has a virtual address space of 232 , or 4,294,967,296
bytes, often abbreviated as 4GB. Above this address, starting at 0xbffff738 in this case
(This boundary is machine and O/S dependent) is where the program environment re-
sides (well discuss that later) and above that still is where the operating system resides (the
kernel) occupying the upper reaches of address space up to the 4GB limit.
The next variable, a double is 64-bits or 8 bytes in length. Note that its address is smaller
(by 8 bytes). The address space that is provided for local variables is called the stack frame
and it grows downwards. Note where the next variable is located.
Each function creates its own stack frame for putting its local variables into memory, releasing
it when the function terminates. This is what is meant by the stack getting destroyed when
a function terminates. The next function call will use this space for its own stack frame.
The executable program, the load module is at the bottom of the address space, starting at
byte 0. This area is called the text segment. Above the text segment are stored initialized
and uninitialized global variables. Above this is the heap space, the address space where
dynamic memory (memory allocated by the program) is located. It grows upwards. If your
programs and data are so big that your stack frames and heap run into each other, you
either have to redesign your program to use less space or purchase a more expensive 64-bit
computer, one with 264 bytes of array space. (In a few years, most computers will be 64-bit
computers.)
Here another example program that demonstrates that global variables are located at a
different place in memory:
//File: addressGlobal.cpp
#include <iostream>
int main(void)
{ float x = 1.0f; // Declare and initialize a float
cout <<
"xs value: " << x << " xs address: " << &x << "\n"
"ys value: " << y << " ys address: " << &y << "\n"
"zs value: " << z << " zs address: " << &z << "\n";
return 0;
}
Note how the global variables, y and z in this case, are located starting at a lower address
0x8049a70 (something like 1 billion). Note how the global stack grows up. Note also how
the double, y, occupies 8 bytes.
//File: returnTwice.cpp
#include <iostream>
int square(int j)
{ cout << "In function square(), j is located at " << &j << "\n";
return j * j;
}
6.4. CALL BY VALUE, CALL BY REFERENCE, REFERENCE PARAMETERS 141
int cube(int k)
{ cout << "In function cube(), k is located at " << &k << "\n";
return k * k * k;
}
int main(void)
{ int i = 3, iSquared, iCubed;
cout
<< "\n\nIn main():\n"
<< " i is located at " << &i << "\n"
<< "iSquared is located at " << &iSquared << "\n"
<< " iCubed is located at " << &iCubed << "\n\n"
<< "Before the call to square and cube:\n"
<< " i = " << i << "\n"
<< "iSquared = " << iSquared << "\n"
<< " iCubed = " << iCubed << "\n\n";
iSquared = square(i);
iCubed = cube(i);
cout
<< "\n After the call to square and cube:\n"
<< " i = " << i << "\n"
<< "iSquared = " << iSquared << "\n"
<< " iCubed = " << iCubed << "\n\n";
return 0;
}
where I have put in a lot of cout statements to let me know where the variables are stored.
Compiling and running it results in the following output:
In main():
i is located at 0xbffff734
iSquared is located at 0xbffff730
iCubed is located at 0xbffff72c
Note that main()s local variables i, iSquared, iCubed reside in main()s stack frame.
Also note that iSquared and iCubed are not initialized by main() and so the memory
locations of these variables contain nonsense bits, junk left over from the previous use of
those memory locations, whatever process that happened to be. The first function called
is square(). It has one local variable called j which it locates in its own stack frame,
starting at address 0xbffff728. square() does its work happily and returns the result of
its computation to main() which then called the function cube(). cube() has one local
variable called k which it locates in its own stack frame, starting at address 0xbffff728,
the same address used by square()! Once square() returned to main(), its stack frame
was destroyed and cube() did the most efficient thing, locating its stack frame at the next
available location, the location just vacated by square().
We now introduce the method of call-by-reference. This is best done by example, so, here
is the above program converted to a single function call that has both the usual value
parameters and also something newreference parameters in the functions parameter list.
//File: returnTwoThings.cpp
#include <iostream>
int main(void)
{ int i = 3, iSquared, iCubed;
cout
<< "\n\nIn main():\n"
<< " i is located at " << &i << "\n"
6.4. CALL BY VALUE, CALL BY REFERENCE, REFERENCE PARAMETERS 143
cout
<< "\nAfter the call to squareCube:\n"
<< " i = " << i << "\n"
<< "iSquared = " << iSquared << "\n"
<< " iCubed = " << iCubed << "\n\n";
return 0;
}
In the above example, in the parameter definition list (int j, int& j2, int& j3), the
variable j is a value parameter receiving the value of the first parameter in the call statement,
the i in squareCube(i, iSquared, iCubed). In squareCube(), the variable j will be
placed in squareCube()s stack frame. The other two parameters in the parameter definition
list, int& j2 and int& j3, are reference parameters. What this means is that the int
variables called j2 and j3 within the function squareCube() refer to the variables located
at the addresses of the variables given to it in the function call. When the compiler calls
the function squareCube() and sees that the parameter list in the function definition is
expecting addresses, it says, Aha, squareCube() is expecting addresses for iSquared and
iCubed and so the addresses are transferred to squareCube(). squareCube() puts these
addresses in its stack frame. When the code inside squareCube() refers to the variables j2
and j3, all it is really doing is renaming temporarily the memory locations referred to in
main() as iSquared and iCubed.
Compiling and running the example results in the following output:
In main():
i is located at 0xbffff734
iSquared is located at 0xbffff730
iCubed is located at 0xbffff72c
In function squareCube():
j is located at 0xbffff720
j2 is located at 0xbffff730
j3 is located at 0xbffff72c
Note the memory locations of the variables local to main() and the fact that squareCube()
thinks that j2 and j3 live in the same place. Note also that in squareCube(), the local
variable j is located at 0xbffff720, 12 bytes below the end of main()s stack frame. Yet,
j, an integer is only 4 bytes long. Can you guess what use squareCube() is making of those
8 bytes of memory?
Finally, note that value parameters and reference parameters can be mixed in any order in the
parameter list. Just make sure, in the function definition, that all the reference parameters
names are preceded by the ampersand, & symbol.
About the only real-life example that I can come up with that relates to this is my relationship
with my stockbroker. I am the main() routine and he, the incompetent bum, is a function
called stockBroker(). Here is his function definition. Ill let you figure out how Im doing
on the stock market.
//File: stockBrokerFunction.cpp
However, I do want you to notice that I provide him with a fee, myFee which is his to keep.
However, he is playing with my money, alexMoney, a reference parameter, the value of which,
I am unhappy to report, is diminishing rapidly. It is still MY money, but I have given the
stockbroker the ability to change it.
6.5. THE RULES OF SCOPE 145
file scope An identifier declared outside of any function definition has file scope. That
is, global variables, function definitions and function prototypes (if you use them!)
placed outside of any function apply for the entire file. It is perfectly fine to define
an int, say, outside of any function or main. This variable can then be used by all
functions and main. If separate files are linked together to form a program, the other
files will not know about file scope identifiers outside of their own files.
function scope The only identifier that is defined for the entire function is a label (an
identifier followed by a colon :), e.g.
ThisIsALabel:
A transfer to a label can be done with the dreaded goto or within the switch statement,
neither of which will be taught in this course.
Labels are defined for the whole function and undefined outside of it.
{ // This is a block
}
Note the use of optional spacing to delineate the separate blocks in the above.
146 CHAPTER 6. EARLY ABSTRACTIONFUNCTIONS
is a function prototype that names three identifiers a, b, and c. These identifiers are
only known within the function prototype. Often programmers name the variables they
are expecting in a function prototype to remember which variables go in which order.
These variable names are ignored by the compiler outside of the function prototype
statement.
This is all very confusing unless we do some examples. So...lets do some examples!
Consider the following code called scope0.cpp:
//File: scope0.cpp
#include <iostream>
int main(void)
{ float x = 1.0, y = 2.0; // Internal to main
cout << "main: pre-call x = " << x << ", y = " << y << "\n";
myFn(x, y); // Main gives values to myFn
cout << "main: post-call x = " << x << ", y = " << y << "\n";
return 0;
}
6.5. THE RULES OF SCOPE 147
main: pre-call x = 1, y = 2
myFn: pre-op x = 1, y = 2
myFn: post-op x = 2, y = 1
main: post-call x = 1, y = 2
main declares two floats, x and y and gives myFn their values. myFn happens to call these
variables by the same name (they could have been different). myFns job is to switch the
values of these two variables. Within its own scope this has been accomplished but the
switch has not been effected in main. This is because the x and y in main and the x and y
in myFn are different.
Consider the following code called scope1.cpp:
//File: scope1.cpp
#include <iostream>
main: pre-call x = 1, y = 2
myFn: pre-op x = 1, y = 2
myFn: post-op x = 2, y = 1
main: post-call x = 2, y = 1
148 CHAPTER 6. EARLY ABSTRACTIONFUNCTIONS
In this example x and y are defined globally (outside of any function). Both main and myFn
can access them and change them. myFns job is to switch the values of these two variables.
Within its own scope this has been accomplished and the switch has been effected in main
as well. This is because the x and y in main and the x and y in myFn are identical.
Consider the following code called scope2.cpp:
//File: scope2.cpp
#include <iostream>
int main(void)
{ cout << "main: pre-call x = " << x << ", y = " << y << "\n";
myFn(x,y); // Main transfers x and y values
cout << "main: post-call x = " << x << ", y = " << y << "\n";
return 0;
}
main: pre-call x = 1, y = 2
myFn: pre-op x = 1, y = 2
myFn: post-op x = 2, y = 1
main: post-call x = 1, y = 2
In this example x and y are defined globally (outside of any function). main can access them
and change them. However, myFn defines its own x and y and hence the global ones are
hidden and myFn cannot access them and change them.
Consider the following code called scope3.cpp:
//File: scope3.cpp
#include <iostream>
6.5. THE RULES OF SCOPE 149
int main(void)
{ float x = 1.0, y = 2.0, z = 0.0; // Local to main
cout << " main: pre-call x, y, z = "
<< x << ", " << y << ", " << z << "\n";
{ // Start of block
float z = 42.0; // Local to {} block
cout << "block: pre-call x, y, z = "
<< x << ", " << y << ", " << z << "\n";
z = x; x = y; y = z; // Variable switch
cout << "block: post-call x, y, z = "
<< x << ", " << y << ", " << z << "\n";
} // End of block
cout << " main: post-call x, y, z = "
<< x << ", " << y << ", " << z << "\n";
return 0;
}
main: pre-call x, y, z = 1, 2, 0
block: pre-call x, y, z = 1, 2, 42
block: post-call x, y, z = 2, 1, 1
main: post-call x, y, z = 2, 1, 0
In this example x, y, and z are defined local to main. Within main there is a nested block
that defines its own scope. Since this block does not define x and y, these variables pass
into the block. However, z is defined within the nested block and the external one is hidden.
However, the nested block has changed the values of x and y when control is passed back to
main.
Consider the following code called scope4.cpp:
//File: scope4.cpp
#include <iostream>
void myFn(void)
{ float z = 0; // Internal to myFn
cout << "myFn: pre-op z = " << z << "\n";
150 CHAPTER 6. EARLY ABSTRACTIONFUNCTIONS
z = 1; // Reset z
cout << "myFn: post-op z = " << z << "\n";
}
int main(void)
{ cout << "First call to myFn\n";
myFn(); // Main calls myFn
cout << "Second call to myFn\n";
myFn(); // Main calls myFn again
return 0;
}
In this example z is defined locally local to myFn which also initialized it to zero. Every time
myFn is called, z is reset to zero and the executable statements are processed.
Consider the following code called scope5.cpp:
//File: scope5.cpp
#include <iostream>
void myFn(void)
{ static float z = 0; // Internal to myFn
cout << "myFn: pre-op z = " << z << "\n";
z = z + 1; // Add to z
cout << "myFn: post-op z = " << z << "\n";
}
int main(void)
{ cout << "First call to myFn\n";
myFn(); // Main calls myFn
cout << "Second call to myFn\n";
myFn(); // Main calls myFn again
6.5. THE RULES OF SCOPE 151
return 0;
}
In this example z is defined locally local to myFn which also initializes it to zero but holds it
static. The specifier static indicates that this variable is to retain its value when it leaves
a routine, preserving its value for the next entry into the routine. The initialization to zero
is only effective the first time the routine is entered.
static is called a storage class and is a qualifier on the variable type that means that its
value is to be saved, not destroyed when the function ends execution.
Consider the following code called scope6.cpp
//File: scope6.cpp
#include <iostream>
using namespace std;
int main(void){
float x = 1.0, y = 2.0, maxxy; // Internal to main
cout << "main: x = " << x << " y = " << y << "\n";
maxxy = max(x, y);
152 CHAPTER 6. EARLY ABSTRACTIONFUNCTIONS
cout << "main: max of x and y = " << maxxy << "\n";
return 0;
}
main: x = 1 y = 2
max: u = 2 v = 1
main: max of x and y = 2
main declares two floats, x and y and gives myFn their values. myFn happens to call these
variables by different names (they could have been the same as in some of the previous
examples). myFns job is to switch the values of these two variables and determine which
is greater. Within its own scope this has been accomplished but the switch has not been
effected in main. This is because the x and y in main and the u and v in myFn are different.
6.6. PROBLEMS 153
6.6 Problems
1. Another essay question
(a) In your own words numbering 50 or less, describe when you would want to make
a function call-by-reference, rather than call-by-value.
(b) Then give an example of a function call-by-reference that accomplishes something
that you could not do using call-by-value.
(c) Give an example of
i. the function prototype,
ii. the function call, and
iii. the function definition (with an empty statement block) that you would write
for your example.
2. Simple functions
Type in the following main routine exactly as shown and add the definitions of two
functions, cubeit0 and cubeit1, each that provides the cube of the argument x. You
may not use the pow() math library function.
#include <iostream>
int main(void)
{ cout << "Input a number to be cubed: ";
double x;
cin >> x;
double result;
cubeit1(x,result);
cout << result << endl;
return 0;
}
% a.out
Input a number to be cubed: 3
27
27
%
(a) Why wont the following code compile and/or work as intended? Fix the bug(s).
#include <iostream>
int main() {
int i = 1, j = 2;
cout << "The sum of ints i = " << i << " and j = " << j << " is: "
<< sumInts(i,j) << "\n";
return 0;
}
(b) Why wont the following code compile and/or work as intended? Fix the bug(s).
#include <iostream>
#include <cmath>
int main(void)
{ float x = 0.0, cosx, sinx;
int returnValue = trigs(x, sinx, cosx);
cout << "sin(" << x << ") = " << sinx << ", "
<< "cos(" << x << ") = " << cosx << "\n";
6.6. PROBLEMS 155
return 0;
}
#include <iostream>
int main(void)
{ int i = 1, j = 2, k = 3, l = 4;
cyclic(i, j, k, l);
cout << "i,j,k,l : " << i << j << k << l << "\n";
return 0;
}
(a) This code attempts to define a function that returns the maximum of two floats
and orders the two floats in descending order (bigger first, smaller second). This
code only works some of the time. There is one design mistake that occasionally
leads to incorrect results. Assume that the scanf statement is always executed
correctly. You may not fix this using a library function that determines maximum.
#include <iostream>
}
else return f1; // f1 must be maximum, no need to switch
}
int main(void)
{ cout << "Input 2 floats: ";
float a, b;
cin >> a >> b;
cout << "Maximum is: " << fMax(a,b) << "\n";
cout << "Descending order is: " << a << ", " << b << "\n";
return 0;
}
(b) The following code compiles error free. Why wont it work as intended?
#include <iostream>
int main(void)
{ int i = 5, j = 3, k = 1;
sort3(i,j,k);
cout << "In ascending order (smallest->largest) "
<< "the three ints are "
<< i << ", " << j << ", " << k << "\n";
return 0;
}
(c) The following code compiles error free. Why wont it work as intended?
#include <iostream>
int main(void)
{ float x = 2.0, xx, xxx;
xxx = squareCube(x,xx);
cout << "Square of x: " << xx << ", Cube of x is " << xxx << "\n";
return 0;
}
The function returns true if b2 4ac > 0 and a 6= 0. Otherwise, it returns false. If
the function returns true, then root1 and root2 contain the roots of the quadratic
equation ax2 + bx + c = 0, which are
b b2 4ac
x1,2 =
2a
q
7. Write your own function
The following algorithm may be used to calculate x = a:
8. Polar coordinates
Write a function that is compatible with the following main routine:
#include <iostream>
#include <cmath>
#include <string>
int main(void)
158 CHAPTER 6. EARLY ABSTRACTIONFUNCTIONS
{ float x, y, r, t;
cout << "x, y: ";
cin >> x >> y;
cout << "x = " << x << " y = " << y << " is in the " << polar(x,y,r,t)
<< ". " << "r = " << r << " t = " << t << " degrees\n";
return 0;
}
The function, polar(), called in the second cout statement above returns a string
that indicates
Afterthe function returns, the float called r contains the radius computed as
r = x2 + y 2. Hint. r = sqrt(x*x + y*y); After the function returns, the float
called t contains the angle in degrees computed as
= 180 tan1 (y/x)/. Hint. Use t = 45*atan2(y,x)/atan(1.0); to calculate this.
Here is an example of how it works:
red% a.out
x, y: 1 1 //User types in "1 1" in response to the "x, y: " prompt
x = 1 y = 1 is in the upper right quadrant. r = 1.41421 t = 45 degrees
Write a function that determines the number of bits that are used to represent an
unsigned int on the computer that executes the program. Your function has to be
compatible with the following main routine.
6.6. PROBLEMS 159
#include <iostream>
int main(void)
{ cout << "The unsigned int size is " << intSize()
<< " bits on this computer\n";
return 0;
}
red% a.out
The unsigned int size is 32 bits on this computer
160 CHAPTER 6. EARLY ABSTRACTIONFUNCTIONS
6.7 Projects
1. Math library functions
The following table lists some of the commonly used functions in C++s math library
which can be accessed by employing #include <cmath> in the preprocessor area of a
C++ file:
Note that the argument to the trigonometric functions above must be in terms of
radians.
360 (degrees) = 2 (radians).
Write a main program that generates the table on the following page similar to that
shown. In other words, you will have to have a for-loop that somehow generates
the doubles -1.0, -0.9, ..., 1.0, calculate and output x, log(x), exp(x), log10(x),
sin(PI*x), cos(PI*x), sqrt(x), and fabs(x).
Some notes:
Note the argument of the sin() and cos(). You were given the method to
generate a good value for in the Wheres Waldo? project in the previous
chapter.
You will have to use the setw() and setprecision() functions as described in
Chapter 5.
You need one other thing to allow the printing of the redundant trailing zeros.
Put in the statement
cout.setf(ios::fixed);
before your first use of cout.
Note that the outputs -Infinity and NaN are provided automatically by cout
when the argument to the math library functions is out of range of its definition.
6.7. PROJECTS 161
A perfect number is a positive whole number that is the sum of its proper divisors.
The set of proper divisors of number N does not include N itself, but does include
1. For example, the proper divisors of 6 are 1,2,3 and 1 + 2 + 3 = 6. So, 6 is a
perfect number. In fact, it is the first perfect number. The second perfect number
is 28 = 1 + 2 + 4 + 7 + 14. The first 4 perfect numbers were known to the ancient
Greek mathematicians. In fact, only 37 of them are known today! A lot is known
about perfect numbers but much more remains a mystery. For example, the following
is known.
(a) The biggest known perfect number, the last discovered, can be written
23021376 (23021377 1), a number that contains 1,819,050 decimal digits.
(b) All known perfect numbers are even.
(c) All known perfect numbers are given by Euclids formula: N = 2k1(2k 1) where
k is some positive integer and 2k 1 also happens to be a prime number. This is
a special kind of prime number known as a Mersenne prime. It is a really good
idea to make use of this fact in designing your computer program, described
below.
A lot is not known about perfect numbers. It is not known whether or not
(a) find the first 5 perfect numbers and print out their proper divisors.
(b) be composed of at least 2 functions additional to main, one that returns true if
its integer argument is a perfect number and a second function that prints out
the proper divisors of a perfect number. You may define more than 2 additional
functions if you wish.
(c) complete execution in less than one minute of CPU time on a run-of-the-mill,
modern computer.
(d) have output that looks similar to the following:
% a.out
6 is a perfect number
6 = 1 + 2 + 3
6.7. PROJECTS 163
28 is a perfect number
28 = 1 + 2 + 4 + 7 + 14
.
.
.
164 CHAPTER 6. EARLY ABSTRACTIONFUNCTIONS
3. Random integration
Write a function that accepts 3 doubles (x, x0 and x1 below) and returns the
double (f (x, x0 , x1 ) below) for the function:
x sin(x)
f (x, x0 , x1 ) = x0 x x1
1+x
int main(void)
{ cout << "Input x, x0, x1: ";
double x, x0, x1;
cin >> x >> x0 >> x1;
cout << "Evaluating the function at x = " << x
<< " between the limits x0 = " << x0
<< " and " << x1 << "\n";
cout << "f(" << x << ") = " << myFunction(x, x0, x1) << "\n";
return 0;
}
(b) A random way to find an area
i. Write a function that will find the position, xmax , which is the position where
the maximum of a function f (x) occurs. This maximum lies between two
limits x0 and x1 where x1 > x0 . Your value for xmax has to be within a
tolerance of 1012 /|x1 x0 |. You can assume that the function has only one
local maximum between x0 and x1 , that the function f (x) 0 between x0
and x1 and that the function is not a constant.
6.7. PROJECTS 165
x sin(x)
f (x) =
1+x
for 0 x , most of which was coded in the last problem. Use 100,000
samples to estimate the area.
HOW TO WORK ON THIS PROBLEM:
i. Try a few different examples for f (x) for which you know the answer (without
knowing calculus!). Good candidates would be:
A. f (x) = x, for 0 x 1.
B. f (x) = 1 x, for 0 x 1.
C. f (x) = x, for 0 x 1/2, f (x) = 1 x, for 1/2 x 1.
ii. Once you are confident that your algorithm works, then try the assigned
function:
x sin(x)
f (x) =
1+x
for 0 x
iii. Write out a pseudocode to help you design your program.
166 CHAPTER 6. EARLY ABSTRACTIONFUNCTIONS
Chapter 7
We have seen that ints are represented by 32 bit words and that they can only represent
a finite range of integral numbers. A signed integer covers the range 231 i (231 1).
Floating numbers have their own restrictions. One bit is used for the sign of the number, 23
bits represent the mantissa1 (the precision or granularity of the number) and 8 bits are used
to define the exponent. Consequently, floats have a range of about 1045 to about 10+38
and a resolution of about 1 part in 107 . (The particular floating-point representation can be
different on different operating systems.)
doubles are represented by 64 bits. 52 for the mantissa, one for the sign and 11 for the
exponent. The granularity is about 2 parts in 1016 and ranges from about 10324 to about
10+308 . (The particular floating-point representation can be different on different operating
systems.)
Some CPU manufacturers, for example Intel (which provides the CPUs for your laboratory
computers and, if you own them, your home computer or laptop), have adopted an IEEE
standard that represents floating point numbers with 80 bits, doing all the internal calcu-
lations at precisions higher than both floats and doubles. This variable type is called
the long double. 64 bits are used for the mantissa, one for the sign and 15 for the ex-
ponent. The granularity is about 1 part in 10 19 and ranges from about 104965 to about
10+4932 . Other manufacturers have larger representations. For example, the Sun machines
maintained by CAEN have 128-bit long doubles.
1
Actually, it is assumed that the leading bit is always 1, so the representation uses 23 physical bits and
one hidden or virtual bit. All the floating-point numbers have a hidden bit.
167
168 CHAPTER 7. MORE VARIABLE TYPES, DATA ABSTRACTION
FLOAT 32-BITS
EXPO-
NENT MATISSA 23 BITS
8 BITS
1 BIT
SIGN
DOUBLE 64-BITS
EXPONENT
11 BITS MATISSA 52 BITS
1 BIT
SIGN
//File: precisionFloat.cpp
#include <iostream>
float precision(void)
{ float one = 1.0f, e = 1.0f, onePlus;
int counter = 0;
do
{ counter = counter + 1;
e = e/2.0f;
onePlus = one + e;
}while(onePlus != one);
cout << "Converged after " << counter << " iterations\n";
return e;
}
int main(void)
{ cout << "Float resolution = " << precision() << "\n";
return 0;
}
7.1. REPRESENTATION OF FLOATING-POINT NUMBERS 169
New stuff:
1. The statement: float one = 1.0f contains the qualifier "f". This means that 1.0 is
a float, typically a 32 bit constant. If the "f" were omitted, the constant would be a
double, typically a 64 bit constant.
//File: precisionDouble.cpp
#include <iostream>
double precision(void)
{ double one = 1.0, e = 1.0, onePlus;
int counter = 0;
do
{ counter = counter + 1;
e = e/2.0;
onePlus = one + e;
}while(onePlus != one);
cout << "Converged after " << counter << " iterations\n";
return e;
}
int main(void)
{ cout << "Double resolution = " << precision() << "\n";
return 0;
}
New stuff:
1. The statement
//File: precisionLongDouble.cpp
#include <iostream>
int main(void)
{ cout << "Long double resolution = " << precision() << "\n";
return 0;
}
New stuff:
1. The statement
declares and initializes two long doubles. The qualifiers "L" specify that the constant
1.0 is to be considered a long double constant, an 80-bit number on my computer.
Note that what is called Float resolution, Double resolution, or Long double resolution
in the above example outputs from the programs is the number that can NOT be resolved
with respect to 1.
To test the range of a float consider the following code called rangeFloat.cpp:
//File: rangeFloat.cpp
#include <iostream>
#include <iomanip>
int main(void)
{ float x = 1.0f, x0;
float y = 1.0f, y0;
int counter = 0;
do
{ counter = counter + 1;
x0 = x; x = x*2.0f; // Multiply by 2
y0 = y; y = y/2.0f; // Divide by 2
cout << setw(4) << counter << ": "
<< setw(12) << x << " :: "
<< setw(12) << y << "\n";
}while(x0 != x || y0 != y);
return 0;
}
1: 2 :: 0.5
2: 4 :: 0.25
3: 8 :: 0.125
4: 16 :: 0.0625
5: 32 :: 0.03125
.
.
.
125: 4.25353e+37 :: 2.35099e-38
126: 8.50706e+37 :: 1.17549e-38
127: 1.70141e+38 :: 5.87747e-39
128: Inf :: 2.93874e-39
129: Inf :: 1.46937e-39
130: Inf :: 7.34684e-40
172 CHAPTER 7. MORE VARIABLE TYPES, DATA ABSTRACTION
.
.
.
147: Inf :: 5.60519e-45
148: Inf :: 2.8026e-45
149: Inf :: 1.4013e-45
150: Inf :: 0
New stuff:
1. The output Inf is the IEEEs way of representing a number that is too large to be
represented. Inf has its own distinctive bit pattern.
2. Note that the floats appear to have more range for small numbers than large
numbers. IEEE allows for a gradual decrease to zero. These numbers below about
6e-39 are called sub-normal, with fewer bits of precision. The leading bits of the
mantissa are padded with zeros for sub-normal numbers.
To test the range of a double consider the following code called rangeDouble.cpp:
//File: rangeDouble.cpp
#include <iostream>
#include <iomanip>
int main(void)
{ double x = 1.0, x0;
double y = 1.0, y0;
int counter = 0;
do
{ counter = counter + 1;
x0 = x; x = x*2.0; // Multiply by 2
y0 = y; y = y/2.0; // Divide by 2
cout << setw(4) << counter << ": "
<< setw(12) << x << " :: "
<< setw(12) << y << "\n";
}while(x0 != x || y0 != y);
return 0;
}
1: 2 :: 0.5
2: 4 :: 0.25
3: 8 :: 0.125
4: 16 :: 0.0625
5: 32 :: 0.03125
.
.
.
1021: 2.24712e+307 :: 4.45015e-308
1022: 4.49423e+307 :: 2.22507e-308
1023: 8.98847e+307 :: 1.11254e-308
1024: Inf :: 5.56268e-309
1025: Inf :: 2.78134e-309
.
.
.
1073: Inf :: 9.88131e-324
1074: Inf :: 4.94066e-324
1075: Inf :: 0
To test the range of a long double (at least an IEEE 80-bit one as implemented on my
machine) consider the following code called rangeLongDouble.cpp:
//File: rangeLongDouble.cpp
#include <iostream>
#include <iomanip>
int main(void)
{ long double x = 1.0L, x0;
long double y = 1.0L, y0;
int counter = 0;
do
{ counter = counter + 1;
x0 = x; x = x*2.0L; // Multiply by 2
y0 = y; y = y/2.0L; // Divide by 2
cout << setw(4) << counter << ": "
<< setw(12) << x << " :: "
<< setw(12) << y << "\n";
}while(x0 != x || y0 != y);
return 0;
174 CHAPTER 7. MORE VARIABLE TYPES, DATA ABSTRACTION
1: 2 :: 0.5
2: 4 :: 0.25
3: 8 :: 0.125
4: 16 :: 0.0625
5: 32 :: 0.03125
.
.
.
16382: 2.97433e+4931 :: 3.3621e-4932
16383: 5.94866e+4931 :: 1.68105e-4932
16384: Inf :: 8.40526e-4933
16385: Inf :: 4.20263e-4933
.
.
.
16443: Inf :: 1.45808e-4950
16444: Inf :: 7.2904e-4951
16445: Inf :: 3.6452e-4951
16446: Inf :: 0
Now thats a lot of numbers. Try these example codes on your own machine. If you get
output that is different, particularly for the long doubles, Id like to know about it!
//File: oneNotOne.cpp
#include <iostream>
#include <iomanip>
7.2. CHAR: THE CHARACTER VARIABLE 175
int main(void)
{ cout << "N? ";
double N;
cin >> N;
float fraction = 1.0/N;
cout << "Will compute " << fraction << " * " << N << " = ";
float sum = 0;
for (int i = 1; i <= N; i = i + 1) sum = sum + fraction;
cout << setprecision(19) << sum << "\n";
return 0;
}
Try running this code for small values of N and big values of N, say N = 107 or 108 . You
will get answers near 1 for small N, but something entirely different for big N! Why? How
could you fix this?
Recall that the representation of floating-point numbers is inexact in computers. If you are
using floats with a precision of about 1 part in 107 , you will start to notice anomalies if
you try to add two things together that differ in size by 6 or 7 orders of magnitude. These
anomalies can be readily observed with floats. Converting to doubles or long doubles
treats the symptom but does not cure the disease! It is always there but often not noticeable
with higher precision numbers. So why not use doubles or long doubles all the time?
Higher precision costs in terms of storage. Sometimes memory requirements dictate the
use of lower precision. There are speed/performance issues to consider as well. This is yet
another one of the compromises one has to make in designing computer programs.
char ch;
The following assigns the character a to the char variable. A literal character is a
character between single quotes.
176 CHAPTER 7. MORE VARIABLE TYPES, DATA ABSTRACTION
ch = a;
The following line declares a character called ch and assigns it the character a
char ch = a;
ch = "a";
\n is a newline
\t is a horizontal tab
\0 is a null. It means nothing! We have to make a special character that
means nothing!
There are lots of others.
char c;
int i;
i = 65;
c = i;
c = 99;
//File: chars.cpp
#include <iostream>
int main(void)
{ for(int i = 0; i < 256 ; i = i + 1)
{ char c = i;
if (i <= 127)
7.2. CHAR: THE CHARACTER VARIABLE 177
cout << "Int " << i << "-->" << c << " in ASCII\n";
else
cout << "Int " << i << "-->" << c << " beyond ASCII\n";
}
return 0;
}
The characters corresponding to integers 0127 are the ASCII standard character
set. (ASCII = American Standard Code for Information Exchange) which is univer-
sally adopted in English-speaking nations. The printing characters are represented by
ASCII codes 32126. Some of the ASCII codes do special things or represent special
characters. For example, 7 is the alert or bell, 8 is the backspace, 9 is the hor-
izontal tab, 10 is a new line, 11 is a vertical tab, 13 is a carriage return, 127 is
the delete. Note the effect of some of these when running chars.cpp.
Strings can be read in with cin and printed with cout. The cin operation continues
on the string until it sees a space or a new-line character (hitting the Return key).
Here is an example that will be discussed in class:
//File: string1.cpp
#include <iostream>
#include <string>
int main(void)
{ string response;
do
{ cin >> response;
cout << response + "\n";
}while (. != response[0]); //Note vector notation
return 0;
}
It is important to understand that the space character is considered by the cin function
to signal the end of a string.
The fact that a space character is considered by the cin operation to signal the end
of a string can sometimes be a nuisance if you want to input spaces. For example, you
might want an entire sentence to be considered a single string. The getline() string
class member function (as declared by <string>) can be used for this purpose. Here
is an example that will be discussed in class:
//File: string2.cpp
#include <iostream>
#include <string>
int main(void)
{ string sentence;
do
{ getline(cin,sentence);
cout << sentence + "\n";
}while (. != sentence[0]);
return 0;
7.3. THE VECTOR CLASS 179
The length() member function returns the length of a string, the number of characters
that it contains. The substr() member function extracts a sub-strings from a string.
Note that strings can be concatenated with the addition operator, although at least
one of the operands must be a string variable. Here is an example that demonstrates
these three new things.
//File: string3.cpp
#include <iostream>
#include <string>
int main(void)
{ cout << "Type in a string: ";
string r1;
cin >> r1;
cout << "Your response was " << r1.length() << " chars long\n";
cout << "Putting them together: " << r1 + " " + r2 << "\n";
return 0;
}
So far we have been dealing with individual floats and ints, declaring them individually,
naming them individually, manipulating them one at a time, individually. Individuality is
nice, but sometimes it is more efficient to refer to a group of similar individuals in a collective
manner. In many applications we wish to use data, many of the same type, in some sort of
systematic or regular way.
180 CHAPTER 7. MORE VARIABLE TYPES, DATA ABSTRACTION
Suppose I wanted to declare variables associated with the individual grades in this class. I
could do the following the following:
This is a really dumb, repetitive way to do it! Anything that seems really repetitive for
a human can probably be done in a better way by a machine. C++ allows you to define
everything at once using the following syntax:
vector<int> gradeForStudent(217);
which declares, in one fell swoop, 217 ints. (We could also have made them floats or
doubles. We can make vectors out of any variable type.) So, we can refer to the collection
of grades by a single identifier, gradeForStudent, in a collective fashion.
But we still have work to do. We still have to enter the numbers somehow into the computer
program. One way is through assignment statements:
which also seems a little dumb, but indicates that we can also refer to the individuals by a
numerical index. (For example, 7of9 in the Borg collective. If you are not a Trekkie, please
ignore the last statement. However, for some strange reason, 7of9 is the only individual Borg
that I can name.)
In fact, for data of this nature, there is always some boring work to be donetyping in all
the grades. Unless there is an automatic way to generate the components of the vector, some
person has to do the boring job of typing it all in. The is called data entry.
The above example, however, shows that vector indices (the integer inside the []s) start with zero.
This leads to off-by-one errors that plague all novice (and some experienced) programmers
in C++. So, just remember that the nth element in a vector is referred to by the index n
- 1.
Another way of entering the data to the vector is by using an input loop. For example:
#include <iostream>
#include <vector>
.
.
.
const int NumberOfStudents = 217;
vector<int> gradeForStudent(NumberOfStudents);
for(i = 0; i < gradeForStudent.size(); i = i + 1)
{ cout << "Input grade for student number << i << ": ";
cin >> gradeForStudent[i];
}
gets the input done in another way, although someone still has to do all the typing.
There is some new stuff here that needs a little explanation. The vectors that we have just
introduced are really a class in C++. A class is defined as data and functions that operate on
the data within the class. The function size() is one of the vector class member functions.
The syntax to have a member function operate on a data variable in its class is: name the
data variable and connect it via the period, ., and then name the member function with
the appropriate argument list, in this case nothing. The size() member function returns
the number of elements in the vector, in this case, 217.
182 CHAPTER 7. MORE VARIABLE TYPES, DATA ABSTRACTION
There is one other new thing in the above code snippet, the introduction of the const
qualifier to a variable. All this means is that the variable is to be help constant after its
initialization. Any attempt to change it would result in an error. This is a safe way to keep
vector sizes safe from programmer error if they are known to be fixed.
The best way to input the numbers is to input them in a separate file and read this file
in during the execution of the code. This would make the code more general and the code
itself would not have to be concerned with having to enter the data faithfully. And, another
program could make use of this data. We will learn how to read and write files later on in
the course.
The name of a vector (e.g. gradeForStudent) follows the naming convention for iden-
tifiers.
Vectors can be global or local, just like individual variables, depending on where
they are declared.
The index also called the subscript is the thing that goes inside the [ ]s.
If you violate the bounds of a vector (write data either below it or above it), one of
two things can happen
At least in the first situation you know something is wrong. In the second you dont
and that could be dangerous.
where vector1 was previously defined, creates a new vector called vector2 with the
same size as vector1 and copies all the elements of vector1 to vector2.
Suppose we have a class of 10 students. I want to compute the average grade of a class test.
Here is a way to do it.
//File: sumGradesGood.cpp
#include <iostream>
#include <vector> //Need this to use the vector "class"
int main(void)
{ const int MaxNoStudents = 10;
vector<int> grade(MaxNoStudents);
int sum = 0;
for (int i = 0; i < grade.size(); i = i + 1)
{ cout << "Grade for student #" << i + 1 << ": "; // Note the "+ 1"
cin >> grade[i];
sum = sum + grade[i];
}
Grade report:
The above example requires that the C++ code know in advance how many students there
are in the class. So, if the number of students change, the code has to be recompiled. Why
not ask the user of the program to input the number of students, then declare the vector
and then do the calculation? Why not? Here is a better way to do it.
//File: sumGradesBetter.cpp
#include <iostream>
#include <vector> //Need this to use the vector "class"
int main(void)
{ cout << "Number of students writing the test: ";
int nStudents;
cin >> nStudents;
vector<int> grade(nStudents);
int sum = 0;
for (int i = 0; i < grade.size(); i = i + 1)
7.3. THE VECTOR CLASS 185
{ cout << "Grade for student #" << i + 1 << ": "; // Note the "+ 1"
cin >> grade[i];
sum = sum + grade[i];
}
Grade report:
Im still dissatisfied with the above program. It requires me to count how many students
wrote the test. Why not have the vector simply grow in size as I enter more data? Why not?
Here is an even better way to do it. In this case, the input loop terminates with a negative
grade or a grade larger than 100.
//File: sumGradesBest.cpp
#include <iostream>
#include <vector> //Need this to use the vector "class"
int main(void)
{ vector<int> grade;
Grade report:
The new features of the above program is a new member function of the vector class, seen
in the statements:
7.3. THE VECTOR CLASS 187
.
.
.
vector<int> grade;
.
.
.
grade.push_back(score);
.
.
.
Note that the first statement above simply declares a vector without a size! We are free to do
this. All it does is bind the identifier grade to a vector variable type. The member function
push back(score) increases the size of the vector by one and initializes the new location
with its argument, in this case, the value of score. There is another member function called
pop back(), with no argument, that reduces a vectors size by one.
Remember that it is usually useful to think of vectors as simple variables. This is especially
true for vectors and functions. Take all the rules you have learned about functions and
variables and apply them to functions and vectors. To demonstrate this, consider the fol-
lowing example that demonstrates numerical integration. All the algorithm does is integrate
a simple function in three different ways. First, it puts the function into a vector with a
certain number of points based on an evenly divided mesh, or grid. Then is forms rectangles
in 3 different ways, using for its height the left mesh point, the right mesh point and the
midpoint. Can you guess why the midpoint method is so much better?
//File: integrate.cpp
#include <iostream>
#include <cmath>
#include <vector>
int main(void)
{ cout << "Number of points in the integration mesh: ";
int mesh;
cin >> mesh;
vector<double> f(mesh), x(mesh);
for(int i = 0; i < mesh; i = i + 1)
{ x[i] = static_cast<double>(i)/(mesh - 1);
f[i] = exp(x[i]);
}
return 0;
7.4. PROBLEMS 189
7.4 Problems
1. The inner product
Complete the program started below. You must complete the function innerProduct()
which computes the inner product of two vectors, x and y. The inner product is the
sum x0 y0 + x1 y1 + ... + xn1 yn1 where xi is the i + 1th element of x and the number
of elements in the vector is n. Here is a function stub and a main routine that you
must use to test your function:
#include <iostream>
#include <vector>
#include <cstdlib>
int main(void)
{ int vectorLength = 10;
vector<float> x (vectorLength);
cout << " x: ";
for (int i = 0; i < vectorLength; i = i + 1)
{ x[i] = rand()%100;
cout << "\t" << x[i];
}
cout << "\n";
vector<float> y(vectorLength);
cout << " y: ";
for (int i = 0; i < vectorLength; i = i + 1)
{ y[i] = rand()%10;
cout << "\t" << y[i];
}
190 CHAPTER 7. MORE VARIABLE TYPES, DATA ABSTRACTION
cout << "Inner product is: " << innerProduct(x,y) << "\n";
return 0;
}
In the comments of your function, answer the question: Why did the function use the
const qualifiers in the parameter list and pass the vectors by reference?
#include <iostream>
#include <vector>
#include <cstdlib>
int main(void)
{ int vectorLength = 8;
vector<int> a(vectorLength);
cout << " a: ";
for (int i = 0; i < vectorLength; i = i + 1)
{ a[i] = rand();
cout << "\t" << a[i];
}
cout << "\n";
cout << "The minimum array element is: " << minimum << "\n";
cout << "The maximum array element is: " << maximum << "\n";
7.4. PROBLEMS 191
return 0;
}
In the comments of your function, answer the question: Why were min and max given
as reference parameters ?
3. Nothing negative
Complete the program started below. You must complete the function nothingNegative()
which accepts a vector called bothSigns containing positive and negative integers and
returns a vector of equal or lesser length that contains only the non-negative integers
of the vector bothSigns. Here is a function stub and a main routine that you must
use to test your function:
#include <iostream>
#include <vector>
#include <cstdlib>
int main(void)
{ int vectorLength = 10;
vector<int> bothSigns(vectorLength);
cout << " Input vector: ";
for (int i = 0; i < vectorLength; i = i + 1)
{ bothSigns[i] = rand()%201 - 100;
cout << "\t" << bothSigns[i];
}
cout << "\n";
}
cout << "\n";
return 0;
}
In the comments of your function, answer the question: Why can this program, when
compiled with just the function stub, go into what looks like an infinite loop?
4. Vector manipulations
Write a function that accepts one called-by-reference vector of ints and returns another
vector of ints. Upon entry to the function, the vector in the parameter list can be
any size and contains ints that can have any value. Upon return, the vector in the
parameter list contains only the positive ints (> 0) in the same order. Upon return,
the returned vector contains only the negative ints (< 0) in the same order as they
appeared in the original called-by-reference vector in the parameter list, when the
function was entered.
Here is an example of how it works:
#include <iostream>
#include <vector>
#include <cstdlib>
7.4. PROBLEMS 193
#include <ctime>
int main(void)
{ srand(time(NULL));
int size = rand()%20 + 10; //size is a RN between 10 and 29
vector<int> in(size), out;
cout << "Original vector is size " << in.size() << endl;
for (int i = 0; i < in.size(); i = i + 1)
cout << in[i] << " ";
cout << "\n\n";
extractNegs(in, out);
cout << "Returned vector is size " << out.size() << endl;
for (int i = 0; i < out.size(); i = i + 1)
cout << out[i] << " ";
cout << "\n\n";
cout << "Modified vector is size " << in.size() << endl;
for (int i = 0; i < in.size(); i = i + 1)
cout << in[i] << " ";
cout << "\n\n";
return 0;
}
int main(void)
{ srand(time(NULL));
int size = rand()%11 + 10; //size is random between 10 and 20
vector<int> in(size);
for (int i = 0; i < in.size(); i = i + 1)
in[i] = rand()%19 - 9; //vector element is random between -9 and 9
cout << "Original vector is size " << in.size() << endl;
cout << "Original vector: ";
for (int i = 0; i < in.size(); i = i + 1) cout << in[i] << " ";
cout << endl;
cout << "Modified vector is size " << in.size() << endl;
cout << "Modified vector: ";
for (int i = 0; i < in.size(); i = i + 1) cout << in[i] << " ";
cout << endl;
cout << "Returned vector is size " << negs.size() << endl;
cout << "Returned vector: ";
for (int i = 0; i < negs.size(); i = i + 1) cout << negs[i] << " ";
cout << endl;
return 0;
}
red% a.out
Original vector is size 13
Modified vector: -9 0 4 9 9 9 0 3 3 -1 -6 5 0
Modified vector is size 7
Modified vector: 4 9 9 9 3 3 5
Returned vector is size 3
Returned vector: 0 9 10
7.4. PROBLEMS 195
7. Perfect squares
Complete the program started below. Write a function that returns a vector<int>
and accepts one constant called-by-reference vector<int>. Upon entry to the function,
the vector in the parameter list can be any size and contains ints that are positive
(> 0). Upon return, the vector that is returned contains the indices of the first vector
whose values are perfect squares.
#include <iostream>
#include <vector>
#include <cstdlib>
#include <cmath>
#include <ctime>
int main(void)
{ srand(time(NULL));
int size = rand()%20 + 10; //size is a RN between 10 and 29
vector<int> in(size);
for (int i = 0; i < in.size(); i = i + 1)
{ in[i] = rand()%90 + 10;
cout << in[i] << " ";
}
cout << endl;
cout << "Returned vector is size " << out.size() << endl;
for (int i = 0; i < out.size(); i = i + 1) cout << out[i] << " ";
cout << endl;
return 0;
}
#include <iostream>
#include <vector>
#include <cstdlib>
int main(void)
{ cout << "Input the minimum and maximum random int: ";
int minRange, maxRange;
cin >> minRange >> maxRange;
vector<int> unsorted(vectorLength);
cout << " Vector beforehand: \t";
for (int i = 0; i < vectorLength; i = i + 1)
{ unsorted[i] = minRange + rand()%(maxRange - minRange + 1);
cout << unsorted[i] << " ";
}
cout << "\n";
sort(unsorted);
9. A prime example
Complete the program started below. You must complete the function getPrimes()
that has the vector<int> return type. This function accepts an int called NPrimes
that is the number of consecutive prime numbers starting with 2. The return vector
contains these prime numbers in order.
You must make your function efficient by using something similar to the following test
to eliminate numbers that are not prime:
7.4. PROBLEMS 197
where N is the candidate prime and divisor is a prime number. The divisor must
not be non-prime.
#include <iostream>
#include <vector>
#include <cstdlib>
int main(void)
{ cout << "Input the number of primes to find: ";
int NPrimes;
cin >> NPrimes;
10. No repeats
Complete the program started below. You must complete the function noRepeats()
that has the void return type. This function accepts a vector called bothSigns con-
taining random ints and eliminates any values in it that are repeated. Here is a
function stub and a main routine that you must use to test your function:
#include <iostream>
#include <vector>
#include <cstdlib>
int main(void)
198 CHAPTER 7. MORE VARIABLE TYPES, DATA ABSTRACTION
{ cout << "Input the minimum and maximum random int: ";
int minRange, maxRange;
cin >> minRange >> maxRange;
vector<int> hasRepeats(vectorLength);
cout << " Vector beforehand: \t";
for (int i = 0; i < vectorLength; i = i + 1)
{ hasRepeats[i] = minRange + rand()%(maxRange - minRange + 1);
cout << hasRepeats[i] << " ";
}
cout << "\n";
noRepeats(hasRepeats);
8.1 Arrays
An array is an extension of the vector concept. An array can represent a list of objects with
a single index, for example, Ai , for i = 1, 2, 3...N. For numerical computation, so called
one-dimensional arrays are used to represent lists of objects (e.g. a list of grades). Two
one-dimensional arrays (e.g. x[i],f[x]) can represent a function f (x) by specifying a grid
of points along the x-axis, x[i], or xi , and the function evaluated at those grid points, f[i],
or fi = f (xi ). These are the most common uses of one-dimensional arrays.
Vectors, which we encountered in the previous lecture, are really one-dimensional arrays.
However, arrays are a lower level construct that comes from C. Simply stated, arrays are or-
dered collections of things you already know about, for example, ints, floats and doubles
with a few special rules related to indexing, initializing and communicating with functions.
A vector, on the other hand, is a standard class in C++ and it comes with powerful member
functions like size(), push back() and pop back(), that operate on the data in vectors. For
this reason, we will not investigate one-dimensional arrays in detail in this course, choosing
instead to focus on the more powerful vector class when dealing with 1-D applications.
The multi-dimensional array is an extension of the one-dimensional array concept. A two-
dimensional array can be thought of as a grid or table of values, a set of rows and columns,
each with its own value. There are many expressions of these. A two-dimensional array can
represent a checkerboard, a chessboard, the board in game of Battleship or Minesweeper, a
football field, or the surface of the earth. (Yes, it is two-dimensional, Christopher; its just
not flat!) We could think of many examples, there being no limit to human creativity. After
this lecture, you will have enough syntax tools and rules to program a game of chess. With
a little more understanding of atmospheric physics (not programming), after this lecture
199
200 CHAPTER 8. MORE DATA ABSTRACTION, ARRAYS, STRUCTURES
you could write a program that predicts the weather! After only about 20 lectures we have
gotten this far! Now this is getting interesting! You have the tools and the rules, now apply
your creative thinking to design algorithms which themselves are only composed of three
thingsthe three pillars of algorithm design: sequence, branch and loop. It really just boils
down to this. It really is that simple and wonderful.
In more abstract terms, a two-dimensional array can represent a table of objects with two
indices, for example, Ai,j . For numerical computation in science and engineering, two-
dimensional arrays are used to represent tables of objects as in the examples above. Two-
dimensional arrays (e.g. x[i][j],f[i][j]) can represent a function of two variables, f (x, y),
by specifying a grid of points in the xy-plane, x[i][j], or xi,j , and the function evaluated
at those grid points, f[i][j], or fi,j = f (xi,j ). However, the most interesting ones for scien-
tists and engineers are square two-dimensional arrays, also called matrices. In this course,
we will restrict our discussion to 2-dimensional arrays. There is nothing new in three and
higher dimensions that we will not see in studying 2-dimensional ones. And, the rules for
one-dimensional arrays can be obtained easily from two-dimensional arrays.
Unfortunately, C++ has not defined a new class to describe these objects. So we will have
to grapple with the more primitive array inherited from C. Later on in the course, we will be
studying Matlab. Matlab is built on two-dimensional arrays as the the fundamental variable
type and has developed a lot of functionality for it, which we will discover later. Matlab is
a very sophisticated program (used by professional engineers worldwide). However, if you
can develop the application in C++, it will always run faster, sometimes much faster. So,
we spend some effort learning how to work with two-dimensional arrays in C++. Besides,
doing so will be an excellent exercise in algorithmic thinkingthe prime reason for teaching
this course.
The ANSI standard calls for arrays of at least 12 dimensions. Believe it or not, there are
actually applications for this!
OK, enough with the sermon, already. Lets dive into the syntax before we learn how to
exploit it for creative expression. Some of the syntax was already introduced above.
left to right and the rows numbered 0 to NROWS - 1 going down the page. Of course, this
visualization is completely arbitrary but helps serve as a memory aid.
a[0][0] a[0][1]
a[1][0] a[1][1]
a[2][0] a[2][1]
0 0
0 0
0 0
1 2
3 4
5 6
The brace notation is nice because it may be used to initialize the array a little more sug-
gestively. For example,
results in
1 0
3 0
5 0
Note that it is important, when initializing arrays in this fashion, to make the array size
declared with ints that are fixed with the const qualifier. Otherwise the compiler will
complain and not complete. Arrays can be declared anywhere in a program, for example:
However, the array will have to be initialized with executable statements. Also, in contrast
to vectors, arrays are not automatically initialized to zero. It must be done either on the dec-
laration statement or explicitly initialized to zero within executable statements. Otherwise,
the array will contain bit patterns that were left in memory following previous use.
8.1. ARRAYS 203
Heres a small program that demonstrates some of the declaration, initialization and ad-
dressing concepts.
//File: whereItsAt.cpp
#include <iostream>
int main(void)
{ const int NROWS = 3;
const int NCOLUMNS = 2;
int a[NROWS][NCOLUMNS] = {{1}, {3}, {5}};
return 0;
}
1:0
3:0
5:0
&a[2][1]: 0xbffff72c
&a[2][0]: 0xbffff728
&a[1][1]: 0xbffff724
&a[1][0]: 0xbffff720
&a[0][1]: 0xbffff71c
&a[0][0]: 0xbffff718
a: 0xbffff718
Note how this multi-dimensional array is stored. Computer memory is organized as if it were
a one-dimensional array. Thus, a multi-dimensional array has to be unfolded into a line
204 CHAPTER 8. MORE DATA ABSTRACTION, ARRAYS, STRUCTURES
and stored. Different languages do this in different ways! C++s convention is to store it
from the outer index to the inner index, reinforcing the vectors of vectors concept. In our
two-dimensional example this means that all the columns in the first row are stored, then
all the columns of the second row and so forth.
It is an important performance issue when writing programs to be aware of this storage order
and use the arrays in the most efficient manner. For example, the following program :
//File: fastArray.cpp
int main(void)
{ const int SIZE = 1000;
float a[SIZE][SIZE];
executes almost twice as fast on my computer than slowArray.cpp which is only different
in the ordering of the two for loops:
//File: slowArray.cpp
int main(void)
{ const int SIZE = 1000;
float a[SIZE][SIZE];
//File: 2d.cpp
#include <iostream>
#include <iomanip>
#include <cmath>
#include <vector>
int main(void)
{ /* Initialize the D array */
float D[SIZE][SIZE] = {0};
for(int i = 0; i < SIZE - 1; i = i + 1)
{ D[i][i] = -1;
D[i][i + 1] = 1;
}
I[i][j] = 1;
// Print results
cout
<< " x "
<< " f "
<< " d "
<< " F\n";
for(int i = 0 ; i <= SIZE - 1 ; i = i + 1)
cout << setiosflags(ios::fixed)
<< setw(11) << x[i] << " "
<< setw(11) << f[i] << " "
<< setw(11) << d[i] << " "
<< setw(11) << F[i] << "\n";
return 0;
}
1 11 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0
1 11 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0
1 11 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0
1 11 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0
1 11 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
x f d F
-1.000000 0.497512 0.258711 0.000000
-0.913043 0.520009 0.283216 0.088480
-0.826087 0.544637 0.311375 0.135840
-0.739130 0.571713 0.343954 0.185554
-0.652174 0.601622 0.381930 0.237869
-0.565217 0.634833 0.426560 0.293072
-0.478261 0.671925 0.479500 0.351500
-0.391304 0.713621 0.542947 0.413554
-0.304348 0.760834 0.619879 0.479714
-0.217391 0.814736 0.714408 0.550560
-0.130435 0.876859 0.832347 0.626809
-0.043478 0.949237 0.982116 0.709351
0.043478 1.034638 1.176305 0.799320
0.130435 1.136925 1.434410 0.898183
0.217391 1.261657 1.787930 1.007892
0.304348 1.417129 2.290509 1.131120
0.391304 1.616304 3.039655 1.271669
0.478261 1.880621 4.228182 1.435201
0.565217 2.248289 6.283189 1.630704
0.652174 2.794654 10.317343 1.873718
0.739130 3.691814 20.073689 2.194744
0.826087 5.437352 56.080322 2.667557
0.913043 10.313904 1031.390381 3.564421
1.000000 100.000000 0.000000 12.260068
we see that the D array differentiates and the I array integrates the function f (x). Yes,
you can do calculus with arrays as long as the spacing of x is such that the function f (x)
does not change to much from element to element. This is the basis of most calculations that
solve differential equations. (You wont be tested on the information in this last paragraph!)
This is what the result look like:
8.2. CHARACTER ARRAYS 209
3
10
2
10 f
1
D*f
10 I*f
0
10
1
10
2
10
3
10
1.0 0.5 0.0 0.5 1.0
string, will look for the end-of-string sentinel until it finds it, possibly reading (or more
dangerously changing) memory locations that were not intended to be accessed. (This
is a major destructive hacking tool! Dont do it!) The string class handles all this
automatically for you, so that is why it is preferable to use the string class whenever
possible.
char s[4];
s[0] = H;
s[1] = i;
s[2] = \0; /* null */
Despite the fact that we have alloted 4 bytes for the string, we have only used 3 of
them because thats where we put the \0 terminator for that string. After the above
statements s[3] is undefined.
Strings define their own length with the \0 terminator which acts as a sentinel for
completion of the string.
which is more convenient than the previous one because there is no need to count the
number of array elements.
which uses the doubles quotes " to enclose what is called a string literal or a string
constant. The above array s[] has length 3. The terminating sentinel \0 is put in
automatically by the compiler.
It is a common mistake to forget about the terminating sentinel \0. For example,
say we defined a character string called mistake in the following:
8.3. STRUCTURES 211
//File: charArray.cpp
#include<iostream>
#include<string>
int main(void)
{ char correct[12] =
{I, A, m, C, o, r, r, e, c, t, !, \0};
char moreData[] = "Will this print?";
char someData[5] = {100, 97, 114, 110, 0};
char mistake[8] = {A, m, i, s, t, a, k, e};
One can make arrays out of chars. For example, a checkerboard could be represented by:
char checkerboard[8][8];
for (int i = 0; i < 8; i = i + 1)
for(int j = 0; j < 8; j = j + 1)
checkerboard[i][j] = ; //Initialize with spaces
checkerboard[0][0] = R; //Place a red checker on the board
checkerboard[7][0] = B; //Place a black checker on the board
8.3 Structures
So far we have been introduced to many forms of variables that contain only one item of
information, bools, chars, ints, floats and doubles. These are fundamental variable
212 CHAPTER 8. MORE DATA ABSTRACTION, ARRAYS, STRUCTURES
types in C++, useful interpretations of bits and bytes that are pre-defined in the definition
of the C++ language.
We have also seen more complex objectsclasses like vectors and strings.
We have also seen arrays of one and two and more dimensions that are made up of only one
of the above fundamental variables types but contain many items referred to by indexing
within the array.
In many cases, these pre-defined variable types are insufficient to elegantly formulate a
solution to an interesting problem. Fortunately, C++ gives the programmer the ability to
make new compound variable types made up of a collection of the existing variable types.
This compound variable type is called a structure.
For example, we could define a structure representing a person and the elements of the
structure could be a string for the persons name, an int for the persons age, floats for
the persons height and weight, more strings for the persons address and occupation and
so on. Structures are the essential composite data type for databases, which represent a
relatively large component of the software industry.
Another example relates to the car racing application of Assignment 6. Lets say that we
wanted to introduce new, racing-like features into the game, like oil slicks that reduce traction
on the road surface, or the ability to draft behind the opponents car. Every grid point
representing a part of the race track would have to carry more information, the coefficient
of friction on the surface, and the direction and number of seconds past the time that a car
passed through it (so that the wind speed could be calculated). While these examples could
be done by separating the information into different variables, why not put them together
in a compound variable? After all, they are all related to one other.
The keyword struct begins a structure definition. The identifier Student is called the
structure tag. It is important to note that this is a definition and not a declaration. All we
are doing at this point is informing the compiler that we will be declaring variable types of
the form Student later on in the program.
8.3. STRUCTURES 213
structs can be defined everywhere although it is conventional to define them outside of any
programming unit such as main or another function so that all programming units will have
access to this variable type.
The variables within the braces {}s are the members of the structure called Student. In
this case the members defined, as suggested by the naming of the member types, are a string
that will contain a name of a student, an int that will contain the section number of the
student and a float that will contain the students grade. The use of a struct seems quite
natural in the application because the various things associated with any given student can
be variables of various types.
The structure tag is used with the keyword struct to declare (and optionally initialize)
variables of the structure type. For example, if we had defined the above structure type
Student, in the main routine or elsewhere we could declare and assign as follows:
struct Student
Dan = {"Smith, Dan", 210, 79.8},
Jan = {"Brown, Jan", 201, 89.3};
declares two structures of the Student type called Dan and Jan and assigns them names,
section numbers and grades.
Individual structure members can be assigned values by using the . notation of the form
structureName.structureMember. For example, if we had not made the assignment in the
declaration statement, we could have assigned values as follows:
Once defined and declared, we can treat these as regular variables, reassigning them, print-
ing them, manipulating them in various ways. For example, we could make the following
redefinitions:
Dan = Jan;
reassigns the entire Dan structure, giving each member the values of the Jan structure.
Consult the complete working code called structure0.cpp that manipulates the Dan and
Jan structures.
Structures can be called by value. This means that the structures are copied locally in the
called function and the structures employed by the calling routine remain untouched. Here
is an example called structure1.cpp:
//File: structure1.cpp
#include<iostream>
#include<string>
int main(void)
{ struct Student
Dan = {"Smith, Dan", 210, 79.8},
Jan = {"Brown, Jan", 201, 89.3};
8.3. STRUCTURES 215
The more conventional way is to use call by reference for structures, saving memory. Here is
the same example as structure1.cpp but using called by reference. It is called structure2.cpp
//File: structure2.cpp
#include<iostream>
#include<string>
int main(void)
{ struct Student
Dan = {"Smith, Dan", 210, 79.8},
Jan = {"Brown, Jan", 201, 89.3};
// I/O statements left out
switchStruct(Dan,Jan);
// I/O statements left out
return 0;
}
//File: structure3.cpp
#include<iostream>
#include<iomanip>
#include<string>
#include<vector>
#include<cstdlib>
{ do
{ sorted = true;
for (int i = 0; i < list.size() - 1; i = i + 1)
if (list[i].grade < list[i+1].grade)
sorted = switchStruct(list[i],list[i+1]);
}while (!sorted);
}
return;
}
int main(void)
{ cout << "How many students in the class? ";
int nStuds;
cin >> nStuds;
vector<struct Student> myClass(nStuds);
//File: survivor.cpp
#include <iostream>
#include <fstream>
#include <iomanip>
#include <cstdlib>
//--------------------------------------------------------------------
//---------------------- Function definitions -----------------------
//--------------------------------------------------------------------
// This function initializes the number of e-s and ions in each cell
void init(struct N grid[][NY])
{ for (int i = 0; i < NX; i = i + 1)
{ for (int j = 0; j < NY; j = j + 1)
{ grid[i][j].nE = NCELL;
grid[i][j].nP = NCELL;
8.3. STRUCTURES 219
}
}
return;
}
//--------------------------------------------------------------------
}
}
return;
}
//--------------------------------------------------------------------
/* This function shifts the electrons to the right and counts how
many are collected. Note that, depending on the step, we can start
at the y index where the number of e-s is non-zero.
*/
int tStep(struct N grid[][NY], int step)
{ int escaped = 0;
for (int i = 0; i < NX; i = i + 1)
{ escaped = escaped + grid[i][NY-1].nE;
for (int j = NY - 2; j >= step; j = j - 1)
grid[i][j+1].nE = grid[i][j].nE;
grid[i][step].nE = 0;
}
return escaped;
}
//--------------------------------------------------------------------
//--------------------------------------------------------------------
//--------------------------- Main routine ---------------------------
//--------------------------------------------------------------------
int main(void)
{ struct N grid[NX][NY]; // grid is an N struct
8.3. STRUCTURES 221
resultsOnFile.open("N.dat");
fGrid(grid, 0); // Write the grid to file
8.4 Problems
1. Multiplying vectors by arrays
Complete the following program. The main routine declares an int array a[ROWS][COLS].
Your program should work for any values for ROWS and COLS, not just the ones pro-
vided. Read through main() to understand what it is doing. The function print()
prints the array to cout. The function randomFill() fills the array with random ints
between 0 and 9. Hint: Use rand()%10. The function mMult() returns a vector whose
value of its ith element is:
Hint: Use for loops to do this. Supply the parameter lists for the three functions.
Answer the following question:
Why is the return vector always full of zeros?
#include <iostream>
#include <vector>
#include <cstdlib>
using namespace std;
const int ROWS = 5; // Set to 5 but can be anything
const int COLS = 4; // Set to 4 but can be anything
int main(void)
{ int a[ROWS][COLS]; // Declare the array
randomFill(a); // Fills array with rand()%10 ints
print(a); // Prints the array
vector<int> x(COLS); // Declare a vector
return 0;
}
int main(void)
{ int I[SIZE][SIZE] = {0}; ident(I); print(I);
int U[SIZE][SIZE] = {0}; upper(U); print(U);
int L[SIZE][SIZE] = {0}; lower(L); print(L);
int H[SIZE][SIZE] = {0}; hatch(H); print(H);
return 0;
}
The 5 functions called by main() produce the output shown following, when SIZE =
10. Write the 5 functions that complete this program. Your program has to work for
any SIZE greater than 0.
(Output from the completed program, when SIZE = 10)
1 0 0 0 0 0 0 0 0 0
0 1 0 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0 0
0 0 0 1 0 0 0 0 0 0
0 0 0 0 1 0 0 0 0 0
0 0 0 0 0 1 0 0 0 0
0 0 0 0 0 0 1 0 0 0
0 0 0 0 0 0 0 1 0 0
224 CHAPTER 8. MORE DATA ABSTRACTION, ARRAYS, STRUCTURES
0 0 0 0 0 0 0 0 1 0
0 0 0 0 0 0 0 0 0 1
1 1 1 1 1 1 1 1 1 1
0 1 1 1 1 1 1 1 1 1
0 0 1 1 1 1 1 1 1 1
0 0 0 1 1 1 1 1 1 1
0 0 0 0 1 1 1 1 1 1
0 0 0 0 0 1 1 1 1 1
0 0 0 0 0 0 1 1 1 1
0 0 0 0 0 0 0 1 1 1
0 0 0 0 0 0 0 0 1 1
0 0 0 0 0 0 0 0 0 1
1 0 0 0 0 0 0 0 0 0
1 1 0 0 0 0 0 0 0 0
1 1 1 0 0 0 0 0 0 0
1 1 1 1 0 0 0 0 0 0
1 1 1 1 1 0 0 0 0 0
1 1 1 1 1 1 0 0 0 0
1 1 1 1 1 1 1 0 0 0
1 1 1 1 1 1 1 1 0 0
1 1 1 1 1 1 1 1 1 0
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 0 1 0 1 0 1 0 1 0
1 1 1 1 1 1 1 1 1 1
1 0 1 0 1 0 1 0 1 0
1 1 1 1 1 1 1 1 1 1
1 0 1 0 1 0 1 0 1 0
1 1 1 1 1 1 1 1 1 1
1 0 1 0 1 0 1 0 1 0
1 1 1 1 1 1 1 1 1 1
1 0 1 0 1 0 1 0 1 0
sums the rows and columns putting the results into two separate vectors, sumRows, a
vector ROWS in length containing the sum of each row, and sumCols, a vector COLS in
length containing the sum of each column: The function print() prints the array to
cout and the vectors as shown in the example below. Note, pretty formatting is not
important, but the numbers have to be correct. Supply the parameter lists for the
three functions.
Example use:
> a.out
2 2 1 3 3 : 11
3 2 3 0 2 : 10
1 3 0 0 1 : 5
3 1 3 1 2 : 10
- - - - -
9 8 7 4 8
#include <iostream>
#include <vector>
#include <cstdlib>
using namespace std;
const int ROWS = 5; // Set to 5 but can be anything
const int COLS = 4; // Set to 4 but can be anything
int main(void)
{ int a[ROWS][COLS];
randomFill(a);
vector<int> sumRows(ROWS);
vector<int> sumCols(COLS);
sumRowsAndCols(a,sumRows,sumCols);
print(a,sumRows,sumCols);
return 0;
}
int main(void)
{ int a[ROWS][COLS] = {0};
vector<int> r(ROWS);
for(int i = 0; i < r.size(); i = i + 1) r[i] = rand()%4; // 0 <= r[i] <= 3
vector<int> c(COLS);
for(int i = 0; i < c.size(); i = i + 1) c[i] = rand()%4; // 0 <= c[i] <= 3
outerProduct(a,r,c);
print(a,r,c);
return 0;
}
red% a.out
v: 1 0 2 2 3 2 1 2
----------------
r[0]: 3| 3 0 6 6 9 6 3 6
r[1]: 1| 1 0 2 2 3 2 1 2
r[2]: 0| 0 0 0 0 0 0 0 0
r[3]: 3| 3 0 6 6 9 6 3 6
r[4]: 1| 1 0 2 2 3 2 1 2
r[5]: 3| 3 0 6 6 9 6 3 6
r[6]: 3| 3 0 6 6 9 6 3 6
r[7]: 1| 1 0 2 2 3 2 1 2
r[8]: 1| 1 0 2 2 3 2 1 2
r[9]: 1| 1 0 2 2 3 2 1 2
5. Complex structs
This problem uses a struct defined as follows:
8.4. PROBLEMS 227
adjustGrades(list);
where list is a vector<struct Student> with size > 0. Your function will do the
following:
8.5 Projects
1. Battleship! Sink this one!
You will write C++ code that will allow you to play the game Battleship! on your
computer following the rules given below.
The game is played on a 10 by 10 array of chars. A battleship is represented by a series
of sizeShip contiguous (joined) points that lie in a horizontal, vertical or diagonal line.
This can be represented by some special character in a 10 by 10 character array, say S.
For example, if the array everywhere was initialized to the character . and you wrote,
board[2][3] = S; board[3][4] = S; board[4][5] = S; board[5][6] = S;
it would represent a battleship on a diagonal occupying the above indices.
For each ship you will ask the computer to generate sizeShip such contiguous points
on a line starting from a random position within the entire array. For example, if you:
#include<cstdlib>
in the preprocessor area, the code:
i = rand()%10; j = rand()%10; board[i][j] = S;
picks a random point in the array called board and assigns it the value S, indicating
that it is one of the points representing a ship. This is the first point on the ship.
The hard part is to pick sizeShip - 1 more points on a line that are contiguous with
the first point and that remain within the array. This you have to figure out on your
own. The orientation of the battleship should be random as well. You have to make
the part of the program that determines the ships position and orientation a separate
C++ function and the array name must be an argument (in the parameter list) of this
function. When you come to the part where you are putting more than 1 ship on the
board, it gets even harder because no 2 ships can occupy the same space.
Now comes the fun part. You (the user of the program) have 50 + shipSize*nShips/2
bombs to toss at the battleship, where nShips is the number of enemy ships. The
battleship position and orientation are random and are kept secret from you until the
code finishes, so you do not know where it is while you are playing. You have to drop
the bomb on the array, which is equivalent to selecting an element of the array, by
asking the user to provide two indices that lie within the board. If that array element
is an S, you have hit the ship and the program informs you that you have hit the ship.
(See the example below.) You have to hit all locations of a ship to sink it and you have
to sink every ship to win the game.
If you hit a ship once, the game strategy simplifies. You look for adjacent points (8
possibilities). If you hit it again, you know the orientation. Now, all you have to do is
make sure you get all the points that lie on the line.
Win or lose, print out a representation of the board that shows clearly: the location
of the ship, the points of the ship that were struck, and the points where bombs were
dropped but missed.
8.5. PROJECTS 229
Here is an example of a typical play of the game. Your computer output does not have
to look exactly as follows. However, you have to follow the above rules explicitly.
Bombs away # 1: i j: 3 4
Bombs away # 2: i j: 7 2
Bombs away # 3: i j: 4 1
Bombs away # 4: i j: 3 6
Bombs away # 5: i j: 9 2
Bombs away # 6: i j: 6 0
Bombs away # 7: i j: 2 6 Ouch, that hurts!
Bombs away # 8: i j: 2 7
Bombs away # 9: i j: 2 5
Bombs away # 10: i j: 3 6
Bombs away # 11: i j: 3 7
Bombs away # 12: i j: 3 5 Ouch, that hurts!
Bombs away # 13: i j: 4 4 Ouch, that hurts!
Bombs away # 14: i j: 5 3 Ouch, that hurts!
The starting grid in a one-person game (note prompt for acceleration at bottom):
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XO XXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXXXXXXX X
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXFFFFFFX
Horizontal and vertical acceleration (-1,0,1):
To start the programming, write a working main routine and a function called initRace
that initializes the grid to the given starting configuration, and a function called
printRace that prints the grid. The walls and barriers have to be exactly as shown
in the figure on the last page. The barrier on the left is 20 columns wide and 35 rows
high. The barrier on the right is 25 columns wide and 35 rows high.
232 CHAPTER 8. MORE DATA ABSTRACTION, ARRAYS, STRUCTURES
Then, program a one-person and a two-person game. Keep track of the total time for
each player. If a player crashes he is out of the race. The first across the finish line
wins! Hint: Program a one-person game first, then adapt your program for two people.
Warning: This game is addictive!
Consider modifying the program to do one of the following. These are quite challenging
but well within your capabilities.
In a one-person game, keep track of the real time it takes to respond and adjust
the algorithm to work with real time. (Use the standard time library ctime. You
will have to look up the standard time functions in a different book.)
Program a one-person-against-the-computer game with multiple plays. Initially,
the computer makes random moves. Once the player has crossed the finish line,
the computer learns the players solution and tries to improve it.
Program some nice graphics for this game. (Good opportunity to read ahead in
Matlab.)
Program a two-person game but one that generates many barriers randomly in a
game with very many columns that scrolls down the screen.
Dream up some other nice variant of the game.
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XO XXXXXXXXXXXXXXXXXXXX X
XO XXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX X
XO XXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX X
XO XXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX X
XO XXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX X
XO XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXX X
X O XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXX X
X O XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXXXXXXX X
X O XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXXXXXXX X
X O XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXXXXXXX X
XXXXXXXXXXXXXXXXOXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXFFFFFFX
Crashed after 10 seconds Note the car buried in the wall! (Ouch!)
234 CHAPTER 8. MORE DATA ABSTRACTION, ARRAYS, STRUCTURES
Almost. Lost control at the very end.
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XO XXXXXXXXXXXXXXXXXXXX O O X
XO XXXXXXXXXXXXXXXXXXXX O O X
X XXXXXXXXXXXXXXXXXXXX X
XO XXXXXXXXXXXXXXXXXXXX O O X
X XXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX X
XO XXXXXXXXXXXXXXXXXXXX O O X
X XXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX X
XO XXXXXXXXXXXXXXXXXXXX O OX
X XXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX X
XO XXXXXXXXXXXXXXXXXXXX O XXXXXXXXXXXXXXXXXXXXXXXXX O
X XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXX X
X O XXXXXXXXXXXXXXXXXXXX O XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXX X
X O XXXXXXXXXXXXXXXXXXXX O XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXX X
X O XXXXXXXXXXXXXXXXXXXX O XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXXXXXXX X
X O O XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXXXXXXX X
X O O XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXXXXXXX X
X O O XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXXXXXXX X
X O O XXXXXXXXXXXXXXXXXXXXXXXXX X
X O O XXXXXXXXXXXXXXXXXXXXXXXXX X
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXFFFFFFX
Crashed after 33 seconds
8.5. PROJECTS 235
Richard Petty, eat your heart out!
(Solution by Ali Mehmet Kutman, Fall 2000 ENG101/CoE student at UoM)
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XO XXXXXXXXXXXXXXXXXXXX X
XO XXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX X
XO XXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX X
XO XXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX X
XO XXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX O O X
X XXXXXXXXXXXXXXXXXXXX O O X
X XXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX O O X
XO XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX OXXXXXXXXXXXXXXXXXXXXXXXXXO X
X XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXX X
XO XXXXXXXXXXXXXXXXXXXX O XXXXXXXXXXXXXXXXXXXXXXXXX O X
X XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXX X
X O XXXXXXXXXXXXXXXXXXXX O XXXXXXXXXXXXXXXXXXXXXXXXX O X
X XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXX X
X O XXXXXXXXXXXXXXXXXXXX O XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXX O X
X O XXXXXXXXXXXXXXXXXXXX O XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXX X
X O O XXXXXXXXXXXXXXXXXXXXXXXXX X
X O O XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXXXXXXX O X
X XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXXXXXXX O X
X XXXXXXXXXXXXXXXXXXXXXXXXX X
X XXXXXXXXXXXXXXXXXXXXXXXXX X
Finished after 31 seconds (Can anyone beat Alis 31 second solution?)
for each of two players, those players being the human (person using the program)
and the machine (the computer). Some of these numbers can be the same, or they
can all be different, depending on what rand() returns.
On each play, the human picks 4 numbers and the machine picks 4 numbers. If
one of the numbers is correct and in the right position, the hidden number is
revealed.
The first to reveal all 4 numbers wins the game. There are three possible outcomes
1) human wins, 2) computer wins, 3) its a tie.
The playing boards must be represented by integer arrays.
The algorithm that the machine employs to play the game must be designed so that
the machine is guaranteed to win in 9 moves, unless the human has already won.
Otherwise, you are free to choose whatever algorithm you like. Look at the ex-
ample below. It gives a big hint as to how to design a simple algorithm that is
guaranteed to work well.
HUMAN MACHINE
===== =======
? ? ? ? ? ? ? ?
------- -------
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
Miscellaneous Topics
The C++ standard library, <cstdlib>, provides a way of producing a random number, ac-
tually a pseudo random number using the rand() function. The rand() function produces
a pseudo random integer between 0 and RAND MAX, inclusive. The constant RAND MAX is also
defined in defined in <cstdlib>.
Here is an example program, called rand0.cpp that calls rand(). Note the inclusion of
<cstdlib>.
//File: rand0.cpp
#include <iostream>
#include <iomanip>
#include <cstdlib> // Need this for the rand() function
int main(void)
{ cout << "RAND_MAX = " << RAND_MAX << "\n\n";
cout << "The first 10 random numbers are...\n";
239
240 CHAPTER 9. MISCELLANEOUS TOPICS
RAND_MAX = 2147483647
Note that RAND MAX and the implementation of rand() is system dependent. You should not
expect the same values on a different computer or even a different version of the operating
system on the same computer.
If you run this program again, you will note that the same random numbers are produced!
This sort of goes against the idea that rand() produces random numbers! Actually, this is
a benefit. Since the behavior is predictable, it makes it easier to debug. Imagine if you were
trying to debug a program that always gave different results! You would go bonkers trying
to find the cause of the error. So, predictable random numbers are good. But, this is why
they are called pseudo random numbers. They are made from a mathematical prescription
that is remarkably simple. Yet, they pass many different tests of randomness. They also
fail some tests as well but not ones that we are likely to try.
If you are not happy with the same random sequence every time, you can seed the random
number to produce another sequence. The <cstdlib> function srand() does this. All you
have to do is to provide a positive integer to the argument list of srand(). Heres an example
called rand1.cpp:
//File: rand1.cpp
#include <iostream>
#include <iomanip>
#include <cstdlib> // Need this for the rand(), srand() functions
int main(void)
{ cout << "RAND_MAX = " << RAND_MAX << "\n\n";
cout << "Input any int to seed the random number generator: ";
int seed;
9.1. GENERATING RANDOM NUMBERS 241
RAND_MAX = 2147483647
Note the different sequence because the user provided the seed 123456789 to srand().
One way to make the start-up of a program that uses rand() appear to be different every
time, is to seed the random number generator with the int that is provided by the time()
function. The time() function is part of the standard library <ctime>. Heres an example
code called rand2.cpp that uses it:
//File: rand2.cpp
#include <iostream>
#include <iomanip>
#include <cstdlib> // Need this for the rand() and srand() functions
#include <ctime> // Need this for the time() function
242 CHAPTER 9. MISCELLANEOUS TOPICS
int main(void)
{ cout << "RAND_MAX = " << RAND_MAX << "\n\n";
srand(time(NULL)); // Seed the random number generator
cout << "The first 10 random numbers are...\n";
Try running rand2.cpp and verify that you get different numbers every time. This unique
start-up feature is very useful for programming games, in order to produce a game that starts
differently every time.
The interesting uses of rand() involve making decisions based on the output of rand() and
this simulates random behavior. In many applications you can use the modulus function to
do this. For example,
card = rand() % 13 + 1
has a one in 13 chance of being a one, a one in 13 chance of being a two, etc Thus, you
could use the above statement to simulate the random dealing of cards and you could assign
a one to an ace, a 2 to a deuce, 11 to a jack, etc If you were dealing with a finite
series of cards, however, you would have to take some care that you do not deal, say, 5 aces
and that would require some extra care with the coding. We wont go into further detail
here on this topic except to say that dealing 5 aces can get you into BIG trouble in certain
circumstances.
Another way of using random numbers, more common to scientific disciplines, is to convert
the random integer to a random double or float, usually converted so that the number lies
between 0 and 1 (may be inclusive or exclusive of one or both of the endpoints).
Here is an example code, called rand3.cpp, that converts the random integer to a double
between 0 and 1 inclusive:
//File: rand3.cpp
#include <iostream>
#include <iomanip>
#include <cstdlib> // Need this for the rand() and srand() functions
#include <ctime> // Need this for the time() function
9.1. GENERATING RANDOM NUMBERS 243
int main(void)
{ cout << "RAND_MAX = " << RAND_MAX << "\n\n";
srand(time(NULL)); // Seed the random number generator
int nRandoms = 10;
cout << "The first " << nRandoms << " random numbers are...\n";
RAND_MAX = 2147483647
If you are as bad a dart player as I am, throwing a dart at a circular object is truly a random
process. Imagine that you have a circle inscribed in a square. It is easy to show that the
ratio of the area of the circle to the area of the square is /4. This suggests a way to estimate
what is by throwing darts! However, it only works well if you are a bad dart player, like
me.
Set up a circular dartboard on a wall. Draw a square on the wall so that the circle defining
the dartboard touches each side of the square only once. Now start throwing the darts
(badly). Ignore all the darts that land outside of the square. Throw a lot of darts! Count
the ones that land on the dartboard and all the ones that land within the square. The ratio
should be close to /4. And, your estimate gets better the more darts you throw. Warning:
244 CHAPTER 9. MISCELLANEOUS TOPICS
Dont do this in your dorms. Dont do this at home. Try it outside against a fence
or something and make sure that other people, pets, your mothers favorite vase, etc. do not
get damaged.
A much safer way is to do it with a computer code. The following code, called randomPi.cpp
calculates by random sampling:
//File: randomPi.cpp
#include <iostream>
#include <cstdlib> // Need for rand() and srand()
#include <cmath> // Need for pow() and atan()
#include <ctime> // Need for time()
int main(void)
{ int nDarts = 10000; // Number of darts to throw
int nInside = 0; // Counter for those that land inside
srand(time(NULL)); // Seed the random number generator
return 0;
}
There are a few new features in this program that you have not seen before.
The statement
#define MYRAND (2.*rand()/RAND_MAX - 1.)
9.1. GENERATING RANDOM NUMBERS 245
in the pre-processor area replaces every occurrence of MYRAND throughout the rest of
the file with (2.*rand()/RAND_MAX - 1.). This happens before compilation. It is
exactly as if you took an editor, looked for every occurrence of MYRAND and pasted in
its replacement (2.*rand()/RAND_MAX - 1.). You can be as creative as you wish with
#define s, but make sure that you understand this as a cut and pasting procedure.
Generally, you should avoid #define s because the C++ parser does not help you
much with syntax errors. But, #define s are a part of the language and using them
can make life a lot easier sometimes. Just be careful with them.
When you throw a dart on a 2-dimensional board, you are really choosing randomly
an x-coordinate and a y-coordinate. So the statements:
double xDart = MYRAND; double yDart = MYRAND;
pick a random point in a square defined by the corners:
(x, y) = (1, 1), (1, 1), (1, 1), (1, 1).
The pow() function, part of the standard library <cmath>, takes the power of the first
argument to degree of the second argument. For example, pow(x,3) computes x3 .
Finally, the standard library math function atan(), also part of <cmath> computes
the arc tangent of its argument, assumed to be in radians. Since tan1 (1) = /4,
4.0*atan(1.0) is a very accurate determination of , as good as the math library can
provide, at least for a double.
Heres what 20,000 points tossed at a circle look like, generated by the program above.
246 20000 random CHAPTER
points within a square
9. MISCELLANEOUS TOPICS
n(inside circle)/n(total) = /4
The same idea may be used to integrate functions by random sampling. The following code,
called randomIntegrate.cpp integrates exp(x) for 0 x 1.
//File: randomIntegrate.cpp
#include <iostream>
#include <iomanip>
#include <cstdlib> // Need for rand() and srand()
#include <cmath> // Need for exp(), the exponential function
// and abs(), the absolute value function
int main(void)
{ int nDarts = 1000000000, under = 0;
double Ans = 1 - exp(-1);
for(int i = 1; i <= nDarts; i = i + 1)
{ double xDart = MYRAND;
double yDart = MYRAND;
if (yDart <= exp(-xDart)) under = under + 1;
if (0 == i%1000000) // Every million times
{ double ans = static_cast<double>(under)/i;
cout << setiosflags(ios::fixed) << setprecision(8)
<< "#" << setw(10) << i
<< ": I = " << setw(10) << ans
<< ", Delta = " << abs(1 - exp(-1) - ans) << "\n";
}
}
return 0;
}
The standard math library functions defined in <cmath>, exp(), for the exponential
ex and abs() for the absolute value, are used.
setw() sets the width of the output of the following item. It has to be set every time!
setw() is defined in <iomanip>.
The program operates very much like the program that found by random sampling. We
find an x and a y randomly. However, the only difference is that we count only those points
that fall under the function as contributing to the area under the curve. The area under the
curve is the fraction of points that fall under the curve, times the area of the rectangle. In
the above example, the area of the rectangle is 1. If the rectangle did not have unit area,
how would you know what to multiply by? Thats what you have to figure out in assignment
4!
Here is some boiler plate pseudocode that gets the job done:
}
//When the execution arrives here, the list is sorted.
N! = N (N 1) (N 2) 3 2 1
where N is an integer.
Mathematicians prefer the second expression because it is better defined (no assumptions
about what means) and it also suggests a mechanism or process for calculating N! C++
mimics this by providing the programmer a mechanism called recursionthe ability for a
function to call itself. Here is how the factorial can be calculated using this technique.
//File: recursiveFactorial.cpp
#include <iostream>
int factorial(int n)
{ if (0 == n) return 1;
else return (n * factorial(n - 1));
}
int main(void)
{ cout << "N? ";
int N;
cin >> N;
cout << N << "! = " << factorial(N) << endl;
return 0;
}
Note how compact the coding is, and how similar it is to the second mathematical definition.
Note also how the 0! is coded in the if statement. This is critical to stop the recursion process.
Try writing out the stack frames for a simple case, say 5!, to see how this works.
There are a few simple, general guidelines for using recursion:
250 CHAPTER 9. MISCELLANEOUS TOPICS
Successive calls to functions should represent progressively simpler cases. (For example,
(N 1)! is simpler than N!)
There is an end to the recursion, the base case, that does not involve a recursive
call. (For example 0! = 1)
If a function calls itself more than once, and the nesting level gets deep, the calcu-
lation can be very inefficient. (See the following example.)
Recursion is a great way to crash a computer or a program! If you do not program the
stopping criterion correctly, you will cause your stack to collide with your heap, and
your program will be in a heap of trouble.
To illustrate the third point above, consider the calculation of the Fibonacci numbers defined
as follows.
where N is an integer. The code can be written using recursive calls as follows:
//File: recursiveFibonacci.cpp
#include <iostream>
int fibonacci(int n)
{ if (1 == n || 2 == n) return 1;
else return (fibonacci(n - 1) + fibonacci(n - 2));
}
int main(void)
{ cout << "N? ";
int N;
cin >> N;
cout << "Fibonacci(" << N << ") = " << fibonacci(N) << endl;
return 0;
}
The fibonacci function calls itself twice. This is a NO, NO! unless N is quite small, like
less than 30. Dont believe it! Try calculating f (1000)!
Although the above program is elegant and compact, we sometimes have to give up clarity for
efficiency, yet another compromise we must sometimes make. Here is how one can program
the Fibonacci numbers using loops.
9.3. RECURSIONA FUNCTION CALLING ITSELF 251
//File: loopFibonacci.cpp
#include <iostream>
int fibonacci(int n)
{ if (1 == n || 2 == n) return 1;
else
{ int fMinus2 = 1;
int fMinus1 = 1;
int f;
for (int i = 3; i <= n; i = i + 1)
{ f = fMinus2 + fMinus1;
fMinus2 = fMinus1;
fMinus1 = f;
}
return f;
}
}
int main(void)
{ cout << "N? ";
int N;
cin >> N;
cout << "Fibonacci(" << N << ") = " << fibonacci(N) << endl;
return 0;
}
Its ugly but its fast. Try comparing the speed of execution of the above two methods. You
will be surprised at the difference.
Recursion relations play a big role in mathematics and consequently there are many examples
that could be coded in C++ and used as examples. However, another important use of
recursion relations relates to graphics. The following example recursively splits a line into
two smaller segments chosen randomly but with the same total length. This is a very simple
model of how a tree grows. The output of this program is the total number of branches
according to the users input of the largest branch length and the smallest branch length.
//File: tree.cpp
#include <iostream>
#include <cstdlib>
else
{ float split = static_cast<float>(rand())/RAND_MAX;
return 2 + (tree(split * L, LMin) + tree((1 - split) * L, LMin));
}
}
int main(void)
{ cout << "LTotal, LMin? ";
float LTotal, LMin;
cin >> LTotal >> LMin;
cout << "Number of branches = " << tree(LTotal, LMin) << endl;
return 0;
}
There are two companion programs that will be demonstrated in class that provide graphical
output from this program. These are called treeGraphics.cpp and anotherTree.cpp,
both posted on the web. In class, the close connection to fractals will be evident from the
graphical output. Fractals are interesting not only mathematically, but have great uses in
communications, encryption and virtual cinematography!
Before closing the section on recursion, it is worthwhile to note that this technique is also
used in numerical simulation, something the author of this lecture is passionate about. In
fact, the coding in the tree programs shares a lot in common with, to cite a few examples,
scattering of light in the atmosphere, the movement of neutrons in a nuclear reactor, the
scattering of electrons and photons in the human body during diagnostic X-ray procedures
or treatment of cancer with radiotherapy beams. Just a few of the details are different. In
order to find out what these details are, you will have to take a later course in numerical
simulation.
Why files?
Except for a few cases where we generated random data using quasi-random numbers,
so far we have been getting data into our programs by typing input at the keyboard
and any output that our programs have generated has gone to the computer screen.
This is really only useful for limited amounts of data, either on the input side or the
output side.
9.4. INPUT AND OUTPUT USING FILES 253
A large quantity of data is handled more easily and more reliably with files.
Moreover, the same data files can be used by more than one program.
Computers only know about bits - binary digits, 0s and 1s. These are the only
fundamental data types understood by computer hardware.
Humans, on the other hand, are more comfortable with characters - and these, as we
have come to know are usually represented by 8 bits, a byte, by computers.
Character fields can be gathered into recordsof related fields, for example, a persons
name, social security number, age, salary, etc as many fields as are needed for a given
application.
Records can be combined into filescollections of records all somehow related, that
can be accessed by a computer program for some application.
Files are collected in directories. A single directory usually contains files with re-
lated data. Directories can also contain sub-directories with their own files and sub-
directories. It is useful to think of a tree structure of directories. Each sub-directory
is another branch of the tree. The root directory is the trunk of the tree.
The disk on a computer can contain several such trees or partitions. The disk
controller, a hardware component in a computer, works with the operating system to
organizing or manage the files on the disk.
A single computer can contain several disks. Some computers, file servers, can house
many.
These disks (or portions of them) may be shared across networks with other comput-
ers either nearby (Local Area Networks [LANs]) or over long distances (Wide Area
Networks [WANs]).
The ability to connect computers and their data together makes possible the establish-
ment of the World Wide Web [WWW], which permits access to some of the data that
resides on a computer connected to the network. This data can be made available to
anyone who knows its Uniform Resource Locator [URL]. The URL not only give the
internet address of the data, but also conveys some information about what form the
data is in.
254 CHAPTER 9. MISCELLANEOUS TOPICS
C++ views a file as a sequential stream of bytes. The end of a file is determined
anywhere by an end-of-file (EOF) marker, or at a specific byte count that the operating
system has been told about in a program.
Files are stored permanently by the operating system, usually on a hard-disk or some
other medium (floppies, tape, CDs, DVDs). The operating system is responsible for
the maintenance of files.
When a file is opened by C++ what it really means is that a request for data is sent to
the operating system and the data is put into a data streamand C++ only concerns
itself with handling the stream, not the hardware storage device. Once data enters
the stream its is the responsibility of C++ to interpret the data using formatting
instructions.
This allows most of C++ to be operating-system independent.
The standard header files iostream (keyboard and screen-related Input/Output [I/O])
and fstream (file-related I/O) contains all the stream-file operating system dependen-
cies and has to be rewritten for each new operating system.
When a C++ program starts with #include <iostream> it knows about three streams:
stdin (standard input) is (usually) the keyboard which can be read using the
cin >> function.
stdout (standard output) is (usually) the screen which can be written to using
the cout << function.
stderr (standard error) is (usually) the screen which is written to using the
cerr << function. The stderr stream is used by C++ to inform the user, via
warning and error messages, that data may contain ambiguities or errors. It is
often useful to make a distinction between stdout and stderr even though they
output, by default, to the same hardware device.
9.4. INPUT AND OUTPUT USING FILES 255
It is possible in C++ to redirect any or all of the stdin, stdout or stderr files.
We will demonstrate how to do this only as required for some specific purpose. It is
operating-system dependent.
It is possible in C++ to define, create and read other files. Just keep in mind that
C++ creates these as streams and lets the operating system handle all the other details
of file management.
A sequential access file is one in which the records do not have a fixed, specified length.
One usually uses such files for writing and reading data that is not changed later and
that is read all at once.
It is the most efficient way of storing files which have variable length records.
Changing the contents of records or the numbers of records can be done, but not very
efficiently.
Accessing the contents of some specific records can be done, but not very efficiently.
Nonetheless, it is a useful form for storage of data with variable record length that is
all read into memory, manipulated and then all written out.
Sequential files contain character data that is human readable and transportable (usu-
ally) from machine to machine and (usually) from architecture to architecture as long
as all the machines understand ASCII character representation. The only essential
difference is the interpretation of the end of record. UNIX uses line feed, MacOS
uses carriage return and DOS/Win uses carriage return followed by line feed.
2. Declare an output file object and name it using an identifier in C++. This is done
using the ofstream keyword. For example,
ofstream myOutputFile;
256 CHAPTER 9. MISCELLANEOUS TOPICS
associates the identifier myOutputFile with a user-declared output file stream. You
should think of this as a declaration, much as a usual variable declaration, or string
or vector object declaration. It can go anywhere in a program. It is good practice to
locate it close to where you use it for the first time.
3. Before writing to the user-define output stream, it must be opened using the .open()
output file object member function. For example,
myOutputFile.open("someData.dat");
opens the output file stream object called myOutputFile. It also connects the out-
put file identifier myOutputFile with a file called someData.dat. Data going to
myOutputFile will be written physically in the file someData.dat located on the com-
puters hard disk (usually). In this example, the file someData.dat would reside in the
same subdirectory as the load module that was used to start the program assuming
that the user started the program with a statement like:
> a.out
You can also use relative or absolute path names for the parameter of the .open()
member function. For example, a typical unix system usage would be:
myOutputFile.open("~/Private/someData.dat");
myOutputFile.open("C:\\eng101\\hw\\hw6\\hw6.dat");
4. Always check to see that the file was opened successfully using the .fail() member
function. The .fail() member function returns a true when the file open failed. For
example,
if (myOutputFile.fail())
{ //File open fail
return 1; // Return to calling function with abnormal termination code.
}
9.4. INPUT AND OUTPUT USING FILES 257
5. Write to the output stream. Remember it is just a stream, just like cout, but with
your own identifier. For example,
int i = 1, j = 2;
myOutputFile << i << ", " << j << endl;
6. When you are finished writing to the file, close the file using .close member function.
For example,
myOutputFile.close();
The .close() member function disconnects the output stream object, in this case,
myOutputFile, with the physical file, in this case, someData.dat. Although the ter-
mination of a program will properly close all files that it opened, it is a good idea to
close files as soon as you are finished with them. This frees up some system resources
for other programs and in the event of a system crash, closed files are left intact or
may be recovered more easily. Files left unclosed during a system crash may be left
incomplete. (This is somewhat system dependent and dependent upon how sudden
the crash is. Power failures are particularly nasty in this regard.)
Here is an example called fileOutput.cpp that illustrates all these concepts, plus a few
other concepts.
//File: fileOutput.cpp
#include <iostream>
#include <fstream>
int main(void)
{ ofstream myOutputFile; // Create an output file object
if (myOutputFile.fail())
{ // File could not be opened
cerr << "File called " << fileName << " could not be opened.\n";
258 CHAPTER 9. MISCELLANEOUS TOPICS
return 0;
}
This code makes use of the .eof() member function which tests to see if and end-of-file
(EOF) marker has been received in the stream that it is referring to, in this case, cin.
.eof() returns true if the EOF has been received and false otherwise. Note how this is
exploited in the above example. This is how you can control file input with an EOF sentinel.
On UNIX systems, EOF is signaled with a <RETURN><CNTL>-d, on MS systems by <CNTL>-z.
Note as well how the filename was obtained by inputting a 1D character array from the
keyboard. It would seem sensible to use a string class object to accomplish this, but many
compilers do not support the use of a string object as an argument to the .open() member
function.
//File: fileInput.cpp
#include <iostream>
9.4. INPUT AND OUTPUT USING FILES 259
#include <fstream>
int main(void)
{ ifstream myInputFile; // Create an input file object
if (myInputFile.fail())
{ // File could not be opened
cerr << "File called " << fileName << " could not be opened.\n";
return 1; // Return to O/S with abnormal return code
}
else
cout << "File called " << fileName << " was successfully opened.\n";
return 0;
}
In order to protect against destroying an existing file when opening a file for writing, you
should first open it for reading. then test to see if the file open fails. If it fails, it means that
that file does not exist and it is safe to write to that filename. If the open does not fail, it
means that the file exists. In this case you should prompt the user to see if the file should
260 CHAPTER 9. MISCELLANEOUS TOPICS
//File: fileSafeOutput.cpp
#include <iostream>
#include <fstream>
int main(void)
{ ifstream testFile; // Create an output file object
ofstream myOutputFile; // Create an output file object
testFile.open(fileName);
if (!testFile.fail())
{ cout << "File called " << fileName << " already exists.\n";
cout << "Overwrite (Input 0 for no, any other int to overwrite): ";
int clobberIt;
cin >> clobberIt;
testFile.close();
if (!clobberIt) return 0;
}
myOutputFile.open(fileName); //Connect the stream to the file
if (myOutputFile.fail())
{ // File could not be opened
cerr << "File called " << fileName << " could not be opened.\n";
return 1; // Return to O/S with abnormal return code
}
else
cout << "File called " << fileName << " was successfully opened.\n";
}while(keepReading);
return 0;
}
//File: commandLine.cpp
#include <iostream>
cout << "This programs name is: " << argv[0] << endl;
.
.
}
When main is called, argc contains the number of tokens (think of these as words) on
the line that ran the program. For example, if you invoked the program with
argc would be 3.
argv[] is an array of addresses. (The * qualifier on a variable means that the identifier
contains one or more addresses.) These addresses contain the addresses of the starts of the
tokens of the command line. Resident at these addresses is the start of the one-dimensional
character arrays that contain the tokens. In the above example, the first token is the name
of the executable file (usually a.out in our examples). The second token would be word and
the third and last token in this example would be anotherWord.
heres a program that can open a file based on a token given to it on the command line:
//File: fileOpen.cpp
#include <iostream>
#include <fstream>
char fileName[20];
if (argc == 1)
{ cout << "What filename do you want to write to: ";
cin >> fileName;
myOutputFile.open(fileName);
}
else if (argc == 2)
{ myOutputFile.open(argv[1]);
}
else
{ cerr << "Usage: a.out [filename]\n";
}
9.5. COMMAND LINE ARGUMENTS 263
if (myOutputFile.fail())
{ // File could not be opened
cerr << "File could not be opened.\n";
return 1; // Return to O/S with abnormal return code
}
return 0;
}
If only one token is detected, the user is prompted to input a filename. If two tokens are
detected, the second is used as a filename. If there are more than two tokens, the program
stops and prints an error message.
264 CHAPTER 9. MISCELLANEOUS TOPICS
9.6 Problems
1. Double factorials
Write a recursive function that returns the double factorial as a function of its int
argument N.
#include <iostream>
int main(void)
{ cout << "N: ";
int N;
cin >> N;
return 0;
}
red% a.out
N: 5
5!! = 15
2. Sorting structs
This problem uses a struct defined as follows:
A Potpourri of Applications
f 0 (x) has the properties mentioned above for certain ranges of its argument. So, finding the
zero of f 0 (x) is exactly the same as finding the position of the extremum (in this case the
maximum) of f (x). The solution you discovered to find the maximum of f (x) involved a
laborious search over the function. The algorithm about to be described, call the binary
chop or mid-point bisection method, works much more efficiently, as we shall see with only
about 40 iterations. The pseudocode for the algorithm is:
1. Start with an initial guess for an x0 and an x1 such that the function is zero for some
x0 x x1 . From the properties of the function, we know that the sign of f (x0 ) is
different from the sign of f (x1 ).
3. If f (xm ) < , where is the convergence criterion, xm is the estimated zero of the
function and the algorithm can stop. Otherwise,
267
268 CHAPTER 10. A POTPOURRI OF APPLICATIONS
//file findZero.cpp
#include <iostream>
#include <cstdlib>
#include <cmath>
double myF(double x)
{ static double zero = 0;
static double f = zero/zero;
static double Pi = 4*atan(1.0);
if (zero <= x && Pi >= x) f = (sin(x)/(1+x) + x*cos(x))/(1 + x);
return f;
}
int sign(double x)
{ if (0 == x) return 0;
else if (0 > x) return -1;
else if (0 < x) return 1;
else
{ cerr << "Stopping since sign can not be determined\n";
exit(EXIT_FAILURE);
}
}
int main(void)
{ double x0, x1, x;
do
{ cout << "Two limits? ";
cin >> x0 >> x1;
}while(badLimits(x0,x1));
double precision;
cout << "Precision? ";
cin >> precision;
return 0;
}
Apart from the idea of the algorithm, there are a few new features in this code. One is the
output stream cerr. cerr is a different output stream than cout and it is intended to be the
stream to which diagnostic or error messages are sent. For example, the int sign() function
above writes to cerr when it can not determine the sign of the function.
The other important use of cerr is when the user of a program has redirected cout to a file
via the unix redirection symbols. For example, output to cout could be captured in a file
names myOutput as follows:
red% a.out > myOutput
270 CHAPTER 10. A POTPOURRI OF APPLICATIONS
However, cerr would still print to the screen so that the user would know something had
gone wrong. If the error message had been written to cout, the user would not know until
he or she opened to file.
Another example is:
red% a.out < myInput > myOutput
which reads cin from the file called myInput rather than the keyboard. Note that the file
names are arbitrary. The names myOutput and myInput are just examples.
Chapter 11
Programming in MATLAB
What is MATLAB?
A MATLAB demo:
271
272 CHAPTER 11. PROGRAMMING IN MATLAB
>> i = 10;
>> disp(i)
10
>>
Statements
ANSI C++:
i = 0;
while(i<10)
{ i = i + 1;
}
MATLAB:
i = 0;
while(i<10)
i = i + 1;
end
ANSI C++:
if (i <= 10)
{ j = 0;
}
else
{ k = 0;
}
MATLAB:
11.2. ARRAYS IN MATLAB 273
if (i <= 10)
j = 0;
else
k = 0;
end
ANSI C++:
int main(void)
{ int i = 0, s = 0;
while(i < 10)
{ i = i + 1;
s = s + i;
}
cout << s << "\n");
return 0;
}
MATLAB:
i = 0;
s = 0;
while(i < 10)
i = i + 1;
s = s + i;
end
disp(s)
Scripts (or script M-files) are MATLAB statements in a file that the MATLAB in-
terpreter will execute
Functions (or function M-files) are used to implement functions.
Function names are derived from file names.
zeros Creates and initializes arrays in MATLAB and fills the array with 0.0s
ones Creates and initializes arrays in MATLAB and fills the array with 1.0s
Some examples:
>> x = ones(10,1)
x =
1
1
1
1
1
1
1
1
1
1
>> whos
Name Size Bytes Class
>> z = zeros(5,3)
z =
0 0 0
0 0 0
0 0 0
0 0 0
0 0 0
>> whos
Name Size Bytes Class
>>
x =
1 2 3 4 5 6 7 8 9 10
>> whos
Name Size Bytes Class
>>
So x = 1:N creates a row with values 1, 2, 3...N
You can use two colon operators (a::b) to make a list of the form:
a, a + , a + 2, a + 3 a + N where a + N b < a + (N + 1).
>> y = 1:2:10
y =
1 3 5 7 9
Note that the upper limit, 10, is not reached because the next number in the
series would overrun it.
linspace creates a 1D array with uniformly spaced elements.
x = linspace(a,b,N)makes N equally spaced points between a and b inclusive.
An example:
276 CHAPTER 11. PROGRAMMING IN MATLAB
>> clear
>> x = linspace(0,1,5)
x =
0 0.2500 0.5000 0.7500 1.0000
>>
Literal creation:
Create an array with one row and 3 columns:
>> x = [1.0,5.2,9.7]
x =
>>
Create an array with 2 rows and 3 columns:
>> y = [1.0,5.2,9.7;3.4,9.3,10.7]
y =
>>
Array indexing
Simple indexing
x(i) refers to the ith element of array x
There is no off-by-one nonsense!
x = ones(1,10) = x = [1,1,1,1,1,1,1,1,1,1]
x(1) is the first element of array x
x(10) is the last element of array x
Array indices go from 1 to the number of rows/columns
>> x = [3,5;7,9]
x =
3 5
7 9
11.2. ARRAYS IN MATLAB 277
Slice indexing
The : symbol as an array index means the whole row or the whole column.
Example,
>> x = [1,2;3,4;5,6]
x =
1 2
3 4
5 6
>> y = x(:,2)
y =
2
4
6
>> z = x(1,:)
z =
1 2
Partial slices can be extracted by specifying ranges. Example,
>> u = x(1:2,1)
u =
1
3
>> v = x(2:3,:)
v =
278 CHAPTER 11. PROGRAMMING IN MATLAB
3 4
5 6
%ch11e1.m
sindat = zeros(2,1000);
sindat(1,:) = linspace(0,2*pi,1000);
sindat(2,:) = sin(sindat(1,:)); % Note: array operation!
save sindat -ascii -double
%ch11e2.m
clear
load sindat
x = sindat(1,:);
y = sindat(2,:);
plot(x,y) % Simple plotting function
pause % Pauses until any keystrike is given
close % Closes the figure
plot(x,y.^2) % Note: ".^2" means element by element squaring operation
pause
close
plot(y,x)
pause
close
Summary
zerosCreate and initialize an array and fill the array with 0.0s
onesCreate and initialize an array and fill the array with 1.0s
clearClear variables from memory
11.3 Loops
for i = array
% Some loop using i where i can not be re-assigned
end
On each successive pass through the loop, i is set to the next column of array. On the first
pass through the loop, i is array(:,1), on the second pass i is array(:,2), etc
This can seem a little confusing unless we remember that the fundamental data type is an
array of doubles.
Here are some simple examples:
sum = 0;
for i = 1:10
sum = sum + i;
end
disp(sum);
i = 1:10;
sum = 0;
for j = i
sum = sum + j;
end
disp(sum);
i = 1:10;
sum = 0;
for j = 1:length(i) % length(array) is a MATLAB function that gives the length
sum = sum + j;
end
disp(sum);
i = [1,2,3,4,5;6,7,8,9,10];
sum = 0;
for j = i % j is set to the columns of i
sum = sum + j(1) + j(2);
end
disp(sum);
>> size(i)
ans =
2 5
If you want to capture both the number of rows and columns, use the following:
>> [nRows,nColumns]=size(i)
nRows =
2
nColumns =
5
length gives the maximum of the number of rows and the number of columns. For example
(using the i array above):
11.3. LOOPS 281
>> length(i)
ans =
5
error error(string) displays the string and causes an error exit from an M-file to the
keyboard. If the string is empty, no action is taken.
Heres an example of an integration script using length and error.
if (length(x) ~= length(f))
error( x and f are different lengths. Stopping.)
end
sum = 0;
for j = 1:(length(f)-1)
sum = sum + 0.5*(f(j) + f(j + 1))*(x(j+1) - x(j));
end
disp(sum);
N = 100;
f = zeros(1,N);
x = linspace(-5*pi,5*pi,N);
for i = 1:N
if (x(i) == 0)
f(i) = 1;
else
f(i) = sin(x(i))/x(i);
end
end
plot(x,f);
g = zeros(N,N);
for i = 1:N
for j = 1:N
g(i,j) = f(i)*f(j);
282 CHAPTER 11. PROGRAMMING IN MATLAB
end
end
surf(x,x,g);
while expression
% Some loop that is executed when expression is true
end
Heres an example
change = 1;
while change >= 0.001
change = change/2;
end
disp(change);
if expression1
% Executed when expression1 is true
elseif expression2
% Executed when expression1 is false and expression 2 is true
elseif expression3
% Executed when expression1&2 are false and expression 3 is true
.
.
.
elseif expressionN
% Executed when expression1...N-1 are false and expression N is true
else
11.5. SOME MATLAB TERMINOLOGY 283
Valid syntax requires the if and the end, zero or more elseifs and zero or one else. The
design is very much like C and therefore does not really need to be discussed further. The
use of indenting make the logical flow a little more comprehensible.
Heres an example that makes a decision based on a random number:
x = rand;
if x < 1/3
disp(x is less than a third);
elseif x < 2/3
disp(x is greater than or equal to a third but less than two thirds);
else
disp(x is greater than or equal to a two thirds);
end
New function:
rand provides an array of uniformly distributed random number between 0 and 1, see
text: Chapter 16.3, p. 171
>> whos
Name Size Bytes Class
s 1x1 8 double array
Grand total is 1 elements using 8 bytes
>> rv = ones(1,8);
>> whos
Name Size Bytes Class
rv 1x8 64 double array
s 1x1 8 double array
Grand total is 9 elements using 72 bytes
>> cv = zeros(10,1);
>> whos
Name Size Bytes Class
cv 10x1 80 double array
rv 1x8 64 double array
s 1x1 8 double array
Grand total is 19 elements using 152 bytes
>> a = rand(3,4);
>> whos
Name Size Bytes Class
a 3x4 96 double array
cv 10x1 80 double array
rv 1x8 64 double array
s 1x1 8 double array
Grand total is 31 elements using 248 bytes
>> a
a =
0.7382 0.9355 0.8936 0.8132
0.1763 0.9169 0.0579 0.0099
0.4057 0.4103 0.3529 0.1389
>> a = 2*ones(2)
a =
2 2
2 2
>> b = a/4
b =
0.5000 0.5000
0.5000 0.5000
>> a*b
ans =
2 2
2 2
>> a+b
ans =
2.5000 2.5000
2.5000 2.5000
>> x = 2*ones(2)
x =
2 2
2 2
>> y = [0,1;2,3]
y =
0 1
2 3
>> x.*y
ans =
0 2
4 6
>> x.^y
286 CHAPTER 11. PROGRAMMING IN MATLAB
ans =
1 2
4 8
>> x.\y
ans =
0 0.5000
1.0000 1.5000
MATLAB has the following precedence for the built-in operators when
evaluating expressions (from highest to lowest):
8. logical OR (|)
y = a&b | c&d
as:
y = (a&b) | (c&d);
288 CHAPTER 11. PROGRAMMING IN MATLAB
The only case where the new precedence will impact the result
obtained is when | appears before & within the same expression
(without parentheses). For example:
y = 1 | x & 0;
y = (1 | x) & 0;
y = 1 | (x & 0);
11.8 M-files
MATLAB commands may be stored in a file and executed. These files are called script
M-files. Any commands that you can enter in the MATLAB command window can be
entered in a file with a filename that is arbitrary except that it should contain the extension
.m, for example myMatlabScript.m. Script M-files may be created with your favorite editor
11.8. M-FILES 289
keyboard gives control to the keyboard. Return to the script M-file by typing return at
the command window prompt, (>>).
pause Pause. Continue after user presses any keyboard key.
waitforbuttonpress Pause. Continue after user presses any keyboard key or mouse key.
%File: russianRoulette.m
clear
echo off
prob = 1/6;
pause
money = 0;
repeat = input(Play? (0 = no, 1 = yes) :);
while(repeat)
disp(Spin....)
pause(1)
if (rand < prob)
disp(BANG! You LOSE!)
return
else
disp(Click! You WIN!)
money = money + 1;
disp(sprintf(Your gain is $%g,money))
end
repeat = input(Repeat? (0 = no, 1 = yes) :);
end
>> russianRoulette
Which each spin you could win 1$
If you lose, you lose everything!
Its best to quit while youre ahead.
Press any key or mouse button to start.
Good luck
[out1,out2,...,outN] = functionName(in1,in2,inM)
and the general syntax of the function definition is to have a separate file called functionName.m
that has the following form:
11.8. M-FILES 293
This line also serves a similar role as the function prototype in C++, checking the com-
patibility of the function definition with the function call. (MATLAB is considerably
looser, however, than ANSI C++).
If the second line of the file is a comment, it is used by MATLAB to look for functions
and functionality using the lookfor MATLAB function.
Comment lines following contiguously are copied to the screen when you type
help functionName
You can have more than one function in a function M-file. However, only the first (the
primary function) is available to other M-files and the command window. The others
are called subfunctions and cannot be used by other functions, scripts or the command
window.
11.9 Problems
1. Check the appropriate circle for the following MATLAB statements.
for p = 1:10
for g = 1:10
x(g,p) = g*p;
end
end
x = 4;
y = [2 3;6 7];
a(1,1) = dumbFunction(x,y(2,1));
function r = dumbFunction(a,b)
r = b/a;
return;
5. What is an algorithm?
List and describe the three capabilities that are needed to construct an algorithm.
How do the MATLAB lookfor and help functions interact with these lines?
>>
11.9. PROBLEMS 297
8. True or false?
9. Multiple choice
Circle all the correct answer(s). There may more than one correct answer but there
will be at least one choice that is correct.
0 1 0 0 0
-1 0 1 0 0
0 -1 0 1 0
0 0 -1 0 1
0 0 0 -1 0
but it does not. The error is
There is an syntax error in the line: if i ~= N a(i,i+1) = 1; end
After a = zeros(5);, nothing is changed in the first row.
There is an syntax error in the line: for i = (2:1:N)
There is a conceptual error in the statement: a(i,i-1) = -1;
None of the above, there is a syntax error somewhere else.
(b) The following code is supposed to sum the squares of the matrix elements of a
random 10 by 10 array and then divide the sum by the number of elements. It
does not work as intended.
clear all;
N = 10;
s = rand(N);
s2 = s*s;
for i = 1:N for j = 1:N sum = sum + s2(i,j); end; end
disp(sum/N^2)
N is not defined properly.
There is a syntax error in the line that starts with for.
sum should be initialized first, before the for loops.
There is a syntax error in the statement disp(sum/N^2).
There is a conceptual error in the statement s2 = s*s;.
There is no error. The code works as intended.
There is a conceptual error in the statement s = rand(N);.
N = 100;
a = zeros(N);
for i = 1:N
for j = 1:N
a(i,j) = 1;
end
end
11.9. PROBLEMS 299
for i = N/4:3*N/4
for j = N/4:3*N/4
a(i,j) = 0;
end
end
clear all;
z = ones(6);
z(3:4,:) = 0;
z(:,3:4) = 0;
disp(z);
sign = 1;
for i = 1:5
x(i) = i - 3;
y(i) = sign*i;
sign = -sign;
end
plot(x,y);
Draw the plot that would result from executing this script.
clear all;
z = -ones(7); % Dont miss the minus sign!
z(2:3,2:3) = 1; z(2:3,5:6) = 4;
z(5:6,2:3) = 2; z(5:6,5:6) = 3;
z(4,4) = 0;
disp(z);
300 CHAPTER 11. PROGRAMMING IN MATLAB
a = [1 2];
b = [1 2 3];
c = 1;
for ai = a
for bi = b
fprintf(a = %f, b = %f\n,ai,bi)
if (bi^2 - 4*ai.*c < 0)
fprintf(No real solution\n\n)
elseif (bi^2 - 4*ai.*c == 0)
fprintf(Single root = %f\n\n,-bi/(2*ai))
else
fprintf(Root1 = %f\n,(-bi - sqrt(bi^2 - 4*ai.*c))/(2*ai))
fprintf(Root2 = %f\n\n,(-bi + sqrt(bi^2 - 4*ai.*c))/(2*ai))
end
end
end
What is the output that would result from executing this script?
There are four bugs in the code, at lines 5, 7, 17 and 18. Find them and fix them.
2
b=rand(1,50)*100; 3
4
[ind,y] = nearest(b(50),x); 5
6
fprintf(The nearest value to %f is b(%i)=%f\n,x,ind,b); 7
clear all;
x = [0,-0.59, 0.95,-0.95, 0.59, 0];
y = [1,-0.81, 0.31, 0.31, -0.81, 1];
plot(x,y)
-40,-40.0
-39,-39.4
-38,-38.9
.
.
.
138,58.9
139,59.4
140,60.0
Hint: The format statement that outputs one line of the table is
fprintf(%3.0f,%4.1f\n,F(i),C(i)).
>> a = rand(2,3)
a =
0.9218 0.1763 0.9355
0.7382 0.4057 0.9169
>> disp(rotateClockWise(a))
0.7382 0.9218
0.4057 0.1763
0.9169 0.9355
>> disp(rotateCounterClockWise(a))
0.9355 0.9169
0.1763 0.4057
0.9218 0.7382
>> disp(flipVertical(a))
0.9355 0.1763 0.9218
0.9169 0.4057 0.7382
>> disp(flipHorizontal(a))
0.7382 0.4057 0.9169
0.9218 0.1763 0.9355
Read through the rest of the MATLAB code and understand what it is trying to
do. The bottom part is for placing the stars.
Write the function star(x,y,r). x and y are the points that define the center of
the star, and r is its radius. Notice that the 5 points on a star are all located on a
circle centered at x and y with radius r. If you drew lines from the center to the
points of the star, those lines would be separated by 72 degrees, (72 = 360/5).
To draw the star, imagine that the top point of the star is numbered 1, the one
to its right 2, and so on. You can make a star easily by drawing a line from point
1, to 4, to 2, to 5, to 3 and back to 1. Heres an example of star(1,3,2).
You might find it useful to to use the sin() and cos() functions. The argument
to these functions should be expressed in radians. In MATLAB, the conversion
from degrees to radians is given by: rads = pi*a/180, where a is an angle in
degrees and rads is the same angle expressed in radians.
You should use the plot() function using white solid lines. Here are the details:
PLOT Linear plot. PLOT(X,Y) plots vector Y versus vector X.
Various line types, plot symbols and colors may be obtained with
PLOT(X,Y,S) where S is a character string made from one element
from any or all the following 3 columns:
4.5
3.5
2.5
1.5
1
1 0.5 0 0.5 1 1.5 2 2.5 3
hold on
Pseudo-code for the three pieces is given below. Construct the MATLAB code.
Script M-file
(a) Prompt the user for an initial guess for the x value at which the zero occurs.
(b) Call the zero-finding function, with the initial guess as the input argument,
and the final answer and number of steps it took to find the final answer as
the output arguments.
(c) Print out the final answer and the number of steps it took to find the final
answer in some self-explanatory format.
Function M-file for Finding a Zero
11.9. PROBLEMS 307
(a) This function has one input argument, the initial guess for x.
(b) This function has two output arguments, the final approximation of the x-
value at which the zero is found, and the number of steps it took to find
it.
(c) Set a convergence criterion of = 106 .
(d) Initialize the number of iterations to zero.
(e) Carry out the following steps until the absolute value of f (x) < where f is
the function you are zeroing, and x is your current approximation of the zero.
Calculate an approximation to the derivative of the function at this point,
from
f (x + ) f (x )
f 0 (x) =
2
Calculate a new approximation to the zero, from
x = x f (x)/f 0 (x)
Update the number of steps that you have taken through the loop.
(f) Return to main
Function M-file f
(a) This function has one input argument, x.
(b) This function has one output argument, y.
(c) The relation is
y = sin(x)/x + x2 ;
Write two versions of MATLAB code that solve this problem. Both versions will employ
a while loop which computes the new average temperature in the bar.
One version will have a for loop (internal to the while loop) over the elements of the
bar. The other version may not employ any for loops, employing instead MATLABs
array indexing method: the colon (:) syntax.
As the starting condition for the while loop, assume that the bar is 0 C everywhere
except at the warmer endpoint, TBar(1000).
clear all;
Nrows = 37; Ncolumns = 93;
a = rand(Nrows,Ncolumns);
[minValue,maxValue,avgValue] = minMaxAvg(a,Nrows,Ncolumns)
%File: quadRoot.m
function [root1,root2] = quadRoot(A,B,C)
%QUADROOT returns the two real roots of A*x^2 + B*x + C = 0
%
% The two roots are root1 = (-B + sqrt(B^2 -4*A*C))/(2*A)
% root2 = (-B - sqrt(B^2 -4*A*C))/(2*A)
%
% An error is detected if 4*A*C > B^2 (imaginary roots)
% A warning is issued if 4*A*C = B^2 (identical roots)
A problem occurs when A is zero. When A is zero there should be only one solution,
x = -C/B unless B is zero as well. If both A and B are zero, there is no solution at all!
Provide a fix-up to these problems by modifying the if/elseif/else construct above.
Definitions:
(a) Make an exact copy of grid into the array called oldGrid.
(b) Loop through every cell in oldGrid.
(c) Find the number of neighbors a cell has by summing the values of the eight
neighboring cells (left, right, up, down, and the four diagonal ones).
(d) If the cell is alive and it has less than 2 neighbors, it dies due to loneliness. (Set
grid(i,j) to zero.)
(e) If the cell is alive and it has 4 or more neighbors, it dies due to overcrowding.
(Set grid(i,j) to zero.)
(f) If the cell is dead and it has exactly 3 neighbors, it comes to life. (Set grid(i,j)
to one.)
310 CHAPTER 11. PROGRAMMING IN MATLAB
You do not have to write any code that produces graphical output. You just have to
code the algorithm described above.
60
1.8
1.6
50
1.4
40 1.2
1
30
0.8
20 0.6
0.4
10
0.2
0
10 20 30 40 50 60
14 1
0.9
12
0.8
10 0.7
0.6
8
0.5
0.4
6
0.3
4
0.2
0.1
2
0
5 10 15 20 25 30 35 40
(d) The color of the background is established by giving it a numerical value of 0.0.
(e) The color of the inner rectangle is established by giving it a numerical value of
0.7.
29. Array striping
Writte the MATLAB code that generates the array that produces the following plot.
It should work for any response to user inputs (see example below).
20
15
10
0
0 5 10 15 20 25 30 35 40
The array contains the data 0 (black stripe) or 1 (white stripe) in a pattern that
produces the above figure. The following response to the prompts produced the output
shown:
Number of stripes: 8
Number of Rows: 24
>>
30. Basketweaving
Write the MATLAB code that generates the array that produces the following basket-
weave plot.
The array contains the data 0 (background), 0.6 (vertical dark grey stripes), or 1
(horizontal light grey stripes) in a pattern that produces the above figure. The following
response to the prompts produced the output shown above:
314 CHAPTER 11. PROGRAMMING IN MATLAB
Hint: The solution is made a lot easier when you realize that there is a small 4 4
array that is repeated to make the full pattern. Look at grid(1:4,1:4).
>> eye(3,4)
ans =
1 0 0 0
0 1 0 0
0 0 1 0
(a) Write a function called littleEye() that does the same thing except the 1s are
on the minor diagonal. Example:
>> littleEye(3,4)
ans =
0 0 0 1
11.9. PROBLEMS 315
0 0 1 0
0 1 0 0
You should do this by having littleEye() call eye() and manipulating array
indices using slice indexing.
(b) Write another function called cross() that sums eye() and littleEye(), except
that the maximum element returned can not be greater than 1. Example:
>> cross(3,3)
ans =
1 0 1
0 1 0
1 0 1
You can avoid using for loops by using the min() function. For example, if A is
a scalar and B is a matrix, C = min(A,B) returns a matrix C that has no value
greater than A.
a = rand(NV,NH);
avgChng = 1;
[a,avgChng] = smooth(a);
plotIt = a;
plotIt(NV+1,:) = 0; % Increase the number of rows by 1
plotIt(:,NH+1) = 1; % Increase the number of columns by 1
pcolor(0:NH,0:NV,plotIt)
colormap(gray)
colorbar
pause(0.01)
end
Assuming:
However, when the (i,j)th point is in the first or last row or column of
the array, the algorithm averages only over the available horizontal or
vertical array points.
>>
Write the function smooth.m. Your function has to respond to the lookfor and help
functions as described above.
where A, B, C and D are scalars, are given by the procedure below (attributed to
Francois Viete, 1615). You will code this algorithm into a MATLAB function called
cubeRoots.m where A, B, C and D are arrays:
where the MATLAB cos(u) and sqrt functions return an array the same di-
mensions as u but with its elements being the cos and of the elements of
u.)
Some notes:
Your function quadraticRoots.m must accept four input arrays, A, B, C and D,
all with identical dimensions. Consequently, you must be careful with your use of
MATLAB operators.
Your function returns three arrays containing either NaNs or roots of the cubic
equation.
Your function must respond sensibly to the MATLAB lookfor and help func-
tions.
To make a variable into a NaN, assign it as follows: root = NaN;
34. Random, Rotated, Really
Write a MATLAB code that executes the following 5-step pseudocode. Each step is
illustrated by a working example.
318 CHAPTER 11. PROGRAMMING IN MATLAB
(a) Using the input() function, interrogate the user for R and C, a row size and
column size, respectively. Example:
Number of rows? 4
R =
4
Number of columns? 3
C =
3
(b) Using the input() function, generate a R C random array. Example:
a =
0.0153 0.4660 0.2026
0.7468 0.4186 0.6721
0.4451 0.8462 0.8381
0.9318 0.5252 0.0196
(c) Rotate the array counter-clockwise. The first column becomes the last row, the
second column becomes the second-to-last row and so on. Example:
a =
0.2026 0.6721 0.8381 0.0196
0.4660 0.4186 0.8462 0.5252
0.0153 0.7468 0.4451 0.9318
(d) Set to zero any array element that has a greater column index than row index.
Example:
a =
0.2026 0 0 0
0.4660 0.4186 0 0
0.0153 0.7468 0.4451 0
(e) Change the sign of any array element that has a value less than 1/2. Example:
a =
-0.2026 0 0 0
-0.4660 -0.4186 0 0
-0.0153 0.7468 -0.4451 0
Accepts a 2-dimensional array of doubles of any size. This array is the only
variable in the input list.
11.9. PROBLEMS 319
Returns the smallest absolute difference that exists between any two array ele-
ments.
Returns the indices of the two closest elements.
Responds sensibly to the lookfor and help functions
Note: abs(x) returns the absolute value of all the elements of x.
CORRELATE correlate, finds the smallest difference between two array elements
Returns the difference and array indices of the two closest elements
>> A = rand(3,4)
A =
0.9501 0.4860 0.4565 0.4447
0.2311 0.8913 0.0185 0.6154
0.6068 0.7621 0.8214 0.7919
>> [d,i1,j1,i2,j2] = correlate(A)
d =
0.0086
i1 =
2
j1 =
4
i2 =
3
j2 =
1
if (nMines < 1)
error(Too few mines)
elseif (nMines > R*C)
error(Too many mines)
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Your part goes here.
% Write your code on the following page(s).
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
disp(grid)
(a) Put nMines randomly on the grid by giving that grid point the value -1. For
example, grid(i,j) = -1 means that the i,jth point on the grid contains a
mine. You will need to use both the rand and int32 functions. (int32()
converts its argument to a 32-bit integer that may be used as an array index.) Be
sure that you deposit exactly nMines mines on the grid, no more, no fewer.
(b) For each grid(i,j) point that is not a mine, count the number of mines sur-
rounding it, those that are in the range grid(i-1:i+1,j-1:j+1). Be careful
with the boundaries of the grid. Note: sum(sum(a)) sums up all the values on
the points of the array called a.
(c) Here is an example use of the program:
>> minesweeper
Number of rows in the grid: 5
Number of columns in the grid: 3
Number of mines: 5
1 -1 1
11.9. PROBLEMS 321
1 2 2
0 2 -1
1 4 -1
-1 3 -1
>>
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Your part goes here.
% Write your code on the following page(s).
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
showGrid = grid;
showGrid(R+1,:) = -1;
showGrid(:,C+1) = 1;
pcolor(0:C,0:R,showGrid)
header = sprintf(\\fontsize{20}There were %d survivors\n,nSurvived);
title(header)
axis off
(a) Between 1:R and 2:C-1 use the random number function rand to decide whether
or not that gridpoint contains a landmine. In other words, if rand < pMine set
the grid point to -1 to indicate the presence of a mine. Otherwise, set it to 0, to
indicate that the gridpoint is safe.
322 CHAPTER 11. PROGRAMMING IN MATLAB
(b) Make the first column of the grid equal to 1. A 1 indicates a person on the
grid. These people are trying to make it to the last column on the grid without
touching a mine.
(c) Within a while loop whose logical condition is that there are still people within
grid(:,1:C-1), use a double for loop to look at every point within grid(:,1:C-1).
If that point has value 1, then do the following:
i. Attempt to advance the person one square to the right (horizontally) and
with equal chance: one square up, one square down, or no vertical change.
Restrict the vertical movements so that the person stays within the grid. Use
of the max() and min() functions, as described in class and in an earlier exam
problem, makes this restriction quite efficient.
ii. If the proposed new location contains another person, then nothing happens.
iii. If the proposed new location contains a landmine, then both the person and
the landmine are eliminated.
iv. If the proposed new location is within the last column, then that person has
safely reached home and should not move anymore.
(d) The game continues until there are no people remaining within grid(:,1:C-1)
(e) Be careful not to move a person more than once during each execution of the
double for loop.
The game is played on an R C array, where R and C are inputs provided by the
user.
The array elements are filled with random numbers using the rand() function.
Go through each element of the array. If the element is greater than 1/2 reset the
array element to +1, else, set it to -1. Each one of these elements is a player in the
game. Those assigned +1 are the Positives. Those assigned -1 are the Negatives.
Both the Positives and Negatives think of each other not only as Opposites but
also as Oppositiondeadly opposition.
Print out the starting number of Positives and Negatives.
The Positives and Negatives are at war and here is how the battle is fought.
An outer while loop is executed under the condition that there are players of both
kinds still in the game.
During each execution of the while loop, the following happens:
(a) Each player tries to moves randomly but with equal chance in one of the 4
directions, North(N), South(S), East(E) or West(W) by one array index.
11.9. PROBLEMS 323
(b) If a player wants to move outside the bounds of the array, then the player
disappears from the game. The penalty for cowardice is severe. (Set that
array element to 0.)
(c) If the array element that the player wants to move to is empty (0), the player
moves there. (The +1 or -1 gets written into the new array element. The old
array element is set to 0.)
(d) If the array element that the player wants to move to is a player of the same
type, then nothing happens.
(e) If the array element that the player wants to move contains an Opposite, then
they fight. Three things can happen, all with equal chance:
i. Mutual destructionboth players perish. (Both array elements get set
to 0.)
ii. The Positive player wins and the Negative player is eliminated from the
game. (The new location gets set to +1 and the old location gets set to
0.)
iii. The Negative player wins and the Positive player is eliminated from the
game. (The new location gets set to -1 and the old location gets set to
0.)
When the while loop ends, there are 3 possible outcomes. Provide a message that
indicates how the game ended and the number of remaining players.
>> war
Number of rows in the game: 10
R =
10
Number of columns n the game: 12
C =
12
The game starts with 64 +s and 56 -s
The -s have annihilated the +s. There are 17 -s remaining.
>>
39. Gaussian sum Write a MATLAB function M-file, called gauss(), that is called as
follows:
which gives the algorithm. Feel free to use the trick if you remember it.
40. Fibonacci sum
Write a MATLAB function M-file, called fibonacci, that is called as follows:
which gives the algorithm. The error function is used to return a message when the
parameter (N in the call statement above) is less than or equal to 0. For example...
>> fibonacci(0)
??? Error using ==> fibonacci
Fibonacci numbers are defined for N >= 1
Your code should work for any positive (> 0) response to the prompts.
The array contains the data 0 (black rectangles) or 1 (white stripes) in a pattern
that produces the above figure. The ith vertical stripe is situated at the index
fibonacci(i) (See preceding problem.) while the ith vertical stripe is situated at
the index gauss(i) (See two problems back.) You may assume (if you wish) that the
gauss() and fibonacci() functions, as described in the 2 previous problems, are on
the Matlab search path.
11.9. PROBLEMS 325
50
45
40
35
30
25
20
15
10
0
0 2 4 6 8 10 12 14 16 18 20
plotIt = a;
plotIt(NRows+1,:) = 0; % Increase the number of rows by 1
plotIt(:,NCols+1) = 0; % Increase the number of columns by 1
pcolor(0:NCols,0:NRows,plotIt)
title(\fontsize{20}Black has value 0, White has value 1)
colormap(gray)
As indicated above, the indices of the array where Waldo is has a value 1, and 0
otherwise.
Waldo is trying to make it to a(16:20,16:20). If he makes it there, the game is
over and Waldo has found his way home.
On each step, Waldo attempts to walk randomly into one of the 8 adjacent squares,
up, down, left, right and the 4 diagonal ones.
If Waldo attempts to walk out of a(1:20,1:20), Waldo is lost and the game is
over.
You do not need to supply any graphical output.
11.10. PROJECTS 327
11.10 Projects
1. Is your dorm room cold?Register your complaint!
Consider that your dorm room is represented by a 3232 array, with 4 walls fixed
at 20 C, a window 161 centered on the left wall which is fixed at 0 C (its freezing
outside), and a heat register comprised of 8 contiguous pixels (array elements that all
touch another heat register array element on at least one side) that is fixed at some
higher temperature. See Figure 1 for an example. Your job is to:
(a) Locate the register in the room somewhere (not occupying the same space as a
wall or a window!) so that the temperature in the room is as uniform as possible,
(b) Heat the room to between 21 and 22 C by raising the temperature of the register.
(c) Full marks for algorithm design will be awarded to those who find a location for
the heat register that keeps the temperature in the room uniform to within 2
degrees. (How to calculate this is discussed later.)
(a) Open a file called a7.m with any editor. This will be your script M-file. Once
in MATLAB, you will run this program by simply typing a7 at the MATLAB
prompt.
(b) To start the problem, first fill a 3232 array with zeros:
N = 32;
T = zeros(N);
(c) Then, make the first and last pixels of each row and column equal to 20, setting
the temperature on the walls, then the 16 pixels of the window (fixed at 0) and
finally the 8 pixels of the register (set at T = 65 C) as shown in Figure 1.
The picture in Figure 1 is displayed using the following MATLAB commands:
plotT = T; % Copy the T array
plotT(N+1,:) = 0; % Increase the number of rows by 1
plotT(:,N+1) = 0; % Increase the number of columns by 1
pcolor(1:N+1,1:N+1,plotT); % Plot it
colorbar;
Increasing the row and columns by 1 is necessary to get MATLAB to show the
walls and the window, otherwise only the interior of the room would show.
(d) Inside a while loop, the i,jth cell gets it value from its neighbors, via an averaging
relation of the form:
T(i,j) = (oldT(i+1,j) + oldT(i-1,j) + oldT(i,j+1) + oldT(i,j-1))/4;
328 CHAPTER 11. PROGRAMMING IN MATLAB
where oldT is the temperature array after the previous pass through the while
loop. You have to program this in the appropriate place in the while loop and you
have to make sure that you do not violate the boundaries of the array. You can
use for loops to do this although it is much more efficient to use slice indexing.
(e) In the above averaging procedure, you may have overwritten some of the array
that was meant to be fixed by the initial conditions, like the register, for instance.
So, you had better make sure that you fix these up in the appropriate place before
the while loop executes another pass.
(f) The while loop is executed until the average change temperature changes less
than 0.00001. The average change is calculated from:
difference = abs(T - oldT);
change = sum(sum(difference))/(N^2);
(Do a help on abs and sum to find out what these functions do.)
(g) If you get everything correct, the final results look like Figure 2 which is plotted
using the commands pcolor(1:N,1:N,T); shading interp; colorbar;.
(h) Calculate and print out the average temperature and its variation:
average = sum(sum(T))/(N^2);
variation = sum(sum(abs(T - average)))/(N^2);
avg
For the above example, I got the average to be Tfinal = 21.1514 while the variation
avg
was Tfinal = 5.39824. You should verify that you get this result before continuing.
While this got the average temperature to within specifications, the variation is
way out of spec. You have to do better. The easiest but most boring way to do it is
to move the register around by typing in the configuration in the script M-file and
running it again until you satisfy both the average and variation specifications.
(BLIFs rule #197 of computer programming: Always do it the easy, boring way
first!) In this case, however, you will need some intuition to get the answers to
within specifications because there are many possibilities, both in the location of
the register and its shape. You should have a look in your dorm or other rooms
to see if you find any common relationships between placement of windows and
heat registers. You should also hope that the architects and engineers thought
about this carefully because the impact on heating costs and human comfort are
quite large.
Alternatively, you can try to find a way of automating the optimization procedure.
How you do this is up to you! Be creative!
Finally, Figure 3 shows a different starting position with the ending results shown in
Figure 4. This is a terrible solution! Not only is the variation worse, but the register
is so hot that you would burn yourself if you got close to it!
11.10. PROJECTS 329
60
30
50
25
40
20
30
15
20
10
10
5
0
5 10 15 20 25 30
Figure 11.1: Typical starting condition for the 3232 room with a register on the right wall
at T = 65 C.
330 CHAPTER 11. PROGRAMMING IN MATLAB
30 60
25 50
20 40
15 30
20
10
10
5
0
5 10 15 20 25 30
Figure 11.2: Final result for a 3232 size room starting with the configuration of Figure 1.
avg avg
In this case, Tfinal = 21.1514 and Tfinal = 5.39824.
11.10. PROJECTS 331
100
30
90
25 80
70
20
60
50
15
40
10 30
20
5
10
0
5 10 15 20 25 30
Figure 11.3: Another starting condition for the 3232 room with a register in one of the
corners at T = 105C.
332 CHAPTER 11. PROGRAMMING IN MATLAB
100
30
90
25 80
70
20
60
50
15
40
10 30
20
5
10
0
5 10 15 20 25 30
Figure 11.4: Final result for a 3232 size room starting with the configuration of Figure 3.
avg avg
In this case, Tfinal = 21.1643 and Tfinal = 6.1069.
11.10. PROJECTS 333
1000
30 800
600
25
400
20 200
15
200
400
10
600
5
800
1000
5 10 15 20 25 30
(g) After the voltage array is calculated, you calculate the magnitude of the electric
field from it. The magnitude of the x-component of the electric field is obtained
from:
Ex(i,j) = V(i+1,j) - V(i,j);
while the magnitude of the y-component of the electric field is obtained from:
Ey(i,j) = V(i,j+1) - V(i,j);
The magnitude of the electric field is obtained from a relation of the form
E(i,j) = sqrt(Ex(i,j)*Ex(i,j) + Ey(i,j)*Ey(i,j));
Be very careful of the array bounds!
(h) Then the magnitude of the electric field is plotted as provided by the template.
(i) If you get everything correct, the final results look like:
120
100
80
60
40
20
20 40 60 80 100 120
120
100
80
60
40
20
20 40 60 80 100 120
Figure 11.7: Electric field grid corresponding to the voltage in the previous figure.
11.10. PROJECTS 337
70
68
66
64
62
60
58
56
58 60 62 64 66 68 70 72
Figure 11.8: A zoom in on the previous picture to show the details of the arc. Even on a
fine 128128 grid you can see evidence of the digitization of the grid.
338 CHAPTER 11. PROGRAMMING IN MATLAB
N = 32; % Array size, should be divisible by 32: 32, 64, 96, 128,...
V = zeros(N); % Creates Voltage array and sets its values to 0
end
figure(2);
pcolor(1:N-1,1:N-1,E);
shading interp;
340 CHAPTER 11. PROGRAMMING IN MATLAB
3. Battleship revisited
You will write MATLAB code that will allow you to play the game Battleship! on
your computer. There is only one ship, the size of the ship is 4 units and you only
have 25 bombs. Otherwise the game rules are exactly the same as for the Battleship
program discussed in Chapter 8.
However, you must use graphical output to show the status of the game board (with
the ship hidden) and use the mouse to generate the bomb drops.
Hints:
N = 10;
showBoard = zeros(N); % Make the board, value of zero for "open sea"
i = 1 + N*rand;
j = 1 + N*rand;
hiddenBoard(int32(i),int32(j)) = 1; %Ship point has value 1
Note that you will have to have two boards, one that you show during the game
and one that is kept hidden, where the ship points reside.
Note the use of the int32() function. The indices of an array should always be
integral. The statements i = 1 + N*rand; j = 1 + N*rand; are intrinsically
doubles. You need the int32() function to convert from doubles to integers.
For more explanation:
11.10. PROJECTS 341
[x,y] = ginput(1);
jDrop = int32(x + 1);
iDrop = int32(y + 1);
The above generates i,j indices on the game board. You can test
hiddenBoard(iDrop,jDrop) to see if that array elements represents open sea
(value 0), a part of the ship (value 1), or something else. In my version of the
game, I used a value of 0.25 to represent a bomb dropped on open sea, and a 0.75
to represent a struck ship.
For more explanation:
>> help ginput
342 CHAPTER 11. PROGRAMMING IN MATLAB
4. Swarm ball
This project was inspired by my 7-year-old daughters soccer team, The Muggles. If you
have ever watched a group of 7-year-olds play soccer, it bears very little resemblance to
the game called soccer. It resembles more closely what would should be called swarm
ball.
In swarm ball, the object of the game is to surround the ball with as many of your
5 other teammates as possible, for the chances of moving the ball in the direction of
the opponents goal is proportional to the number of your team surrounding the ball.
Of course, the other team has a similar strategy. So, around the ball is a swarm of
players all kicking at the poor thing. The ball usually blurts out in one direction and
the swarm reassembles around the ball. Goaltenders, while still a part of swarm ball,
are almost completely irrelevant. The ball is always rolling on the ground. Would you
bend down to pick up a soccer ball surrounded by 24 flailing feet? I think not.
So, this projects task is to program a simulation of swarm ball with the following
requirements.
(a) A 2-dimensional array, called field, contains the game, the players, the ball and
the goalposts. The width and length of the field are defined by:
fieldWidth = 31; % Width of the field
fieldLength = 41; % Length of the field
(b) The following values of the elements of field determine what that point occupies.
Use the following as it gives a sensible rendition when field is plotted using
pcolor:
grass = 0.5; % Grass color
ball = 0.62; % Soccer balls color
red = 0.8; % Reds team color
blue = 0.2; % Blues team color
redGoal = 0.7; % Reds goal color
blueGoal = 0.4; % Blues goal color
boundary = 0; % Field boundary
(c) Define the field, the boundaries and the goals as follows:
field = zeros(fieldWidth,fieldLength);
field(2:fieldWidth-1,2:fieldLength-1) = grass;
field(10:22,1) = redGoal;
field(10:22,end) = blueGoal;
(d) Define the starting position of the game using the following indices:
ballX = 21;
ballY = 16;
11.10. PROJECTS 343
(a) A baseball is struck at a height of 3 feet about the ground. It can have any velocity
between 0 (Bielajew territory) and 250 feet/second (McGuire/Sosa territory). It
can have any angle with respect to the ground from 0 (parallel to the ground) to
90 degrees (straight up in the air).
Using the equations of motion described below, write a MATLAB function that
starts something like this. (It can be different.)
function d = homeRunDistance(y0,theta,v,G,D)
%HOMERUNDISTANCE returns distance a ball travels (hits the ground)
% homeRunDistance(y0,theta,v,G,D) calculates distance a baseball travels
% before it hits the ground assuming that:
% y0 is the initial height of the ball (ft)
% theta is the angle in degrees of the start of the trajectory with
% respect to the ground (90 is straight up)
% v is the initial speed (ft/s)
% G is the magnitude of the acceleration due to gravity (ft/s/s)
% D is the magnitude of the drag factor (1/ft)
%
% The components of acceleration are:
%
% ax = -D*vx*v (x-direction in units ft/s/s)
% ay = -D*vy*v - G (y-direction in units ft/s/s)
%
% where
%
% vx = v*cos(pi*theta/180) (x-direction velocity in units ft/s)
% vy = v*sin(pi*theta/180) (y-direction velocity in units ft/s)
Using a script M-file to call the function homeRunDistance, make a 3D plot of
distance versus theta and v between the limits described above. (A 20 by 20
array should be sufficient.)
(b) For an initial velocity of 250 ft/s, what angle should the ball be hit for maximum
distance? You can determine the maximum in any way you please as long as it is
346 CHAPTER 11. PROGRAMMING IN MATLAB
part of the same script M-file used above and it gives you approximately the right
answer! When you obtain this angle make a 2D plot of the trajectory of the ball
both with and without air resistance (D = 0). Plotting the trajectory means
making a 2D plot where the y-axis is the height and the x axis is the distance.
Without air resistance it would have a parabolic shape.
We can solve for the time of flight, tflight , it takes for a ball to return to the ground
using the quadratic equation and obtain the time and distance as follows:
q
2
vy,0 + vy,0 + 2Gy0
tflight =
G
d = vx,0tflight
For example, if we use y0 = 3 (ft), vx,0 = vy,0 = 250/ 2 (ft/s), and G = 32.174
(ft/s/s) we get d = about 1950 feet for the distance! The inputs are realistic and so
we know that air resistance must play a big role. However, knowing that there is an
exact answer in the case of no wind resistance will serve as an important test of our
stepping algorithm described later.
where D is a measure of the resistance of the air. The total air resistance is proportional
to v 2 and points in the direction opposite to the instantaneous direction of the ball.
The drag factor is related to the physical characteristics of the ball (or projectile) and
has the form:
1
D = CD,ball air Aball /mball
2
where air air is the density of the air, Aball is the cross sectional area of the ball, mball
is the mass of the ball and CD,ball is the drag coefficient, a unitless quantity. For
smooth spheres, CD,ball is always very close to 0.5. However, for a baseball its closer
to 0.35 because of the seams. A pitcher can also change CD,ball by adding a little extra
to it (saliva, vaseline) or taking a little away (cutting the ball). Baseballs that are
newly manufactured have a shine that is rubbed off before the start of the game by the
umpires and occasionally by the pitchers. This IS legal. All they are doing is making
the CD,ball a little bit smaller to make the pitches faster.
The D for a major-league baseball can be worked out easily form the above relations.
Use D = 0.0019285 and G = 32.174 for this problem.
If we assume that the acceleration is constant over a small time interval, t, then make
a stepping algorithm as follows:
(a) Start with the initial conditions x0 = 0, y0 = 3, vx,0 = v0 cos and vy,0 = v0 sin ,
t0 = 0, and a step counter i initialized to 0.
(b) Increment the step counter i = i + 1.
(c) Calculate the acceleration at the start of the step:
q
ax,i = Dvx,i1 vx,i1
2 2
+ vy,i1
q
ay,i = Dvy,i1 vx,i1
2 2
+ vy,i1 G
348 CHAPTER 11. PROGRAMMING IN MATLAB
1
xi = xi1 + vx,i1 t + ax,i (t)2
2
1
yi = yi1 + vy,i1 t + ay,i (t)2
2
vx,i = vx,i1 + ax,i t
vy,i = vx,i1 + ay,i t
There are a few subtleties you will have to work out. One is to guarantee that the
y never becomes negative. The other is to make a reasonable choice for t. Justify
your choice. Recall that we are assuming that the acceleration is constant over the
step. It isnt. However, a proper choice for t make sure that the acceleration is
nearly constant. This weeks lectures will be riddled with hints on the solution of this
problem!
11.10. PROJECTS 349
30 3.5
3
25
2.5
20 2
1.5
15
1
0.5
10
5
0.5
1
5 10 15 20 25 30
Figure 11.9: Two chambers and a pipe (evacuated, value = 0) surrounded by walls (solid,
value = -1).
together with a pipe. The ones I made were made up of 2D arrays and look like those
depicted in first figure. In my example I used chambers that were 30 units high and 10
units wide. The pipe was 16 units high and 10 units wide. (A unit is the width of
350 CHAPTER 11. PROGRAMMING IN MATLAB
a cell.) Thus the entire geometry of the pipe, the two chambers and enclosing walls
could be represented by a 32 32 array in MATLAB. The space within the walls is
given the value 0 for vacuum and the walls are given the value -1.
Now, fill one of the chambers with molecules, placed randomly. In the example in
second figure, I placed 100 molecules. Note that I allowed more than 1 molecule per
cell. Each cell contains a number that represents the number of molecules within the
cell. Since MATLABs random number generator seeds differently every time, your
distributions will look different.
30 3.5
3
25
2.5
20 2
1.5
15
1
0.5
10
5
0.5
1
5 10 15 20 25 30
Now, a time-step is executed. During this time-step, each individual molecule can move
randomly in any direction by one cell, upwards, downwards, sideways, or diagonally.
If the new direction would cause the molecule to hit one of the walls, the proposed
step is invalid and a new direction should be picked randomly. If a molecule enters
the rightmost column of cells, it sticks to the cold wall and can no longer be moved.
The third figure shows the distribution of molecules after 2000 time-steps.
Finally, the simulation ends when all the molecules are trapped in the cold trap. The
final configuration of my example is shown in the fourth figure.
Here is what you must do to complete this problem.
11.10. PROJECTS 351
30
5
25
4
20
3
15 2
10 1
0
5
1
5 10 15 20 25 30
Figure 11.11: After 2000 time steps, 73 molecules have stuck to the cold wall in the cold
trap and 27 are still free.
352 CHAPTER 11. PROGRAMMING IN MATLAB
30
7
6
25
20
4
15 3
2
10
5 0
1
5 10 15 20 25 30
Figure 11.12: After about 8000 time-steps all the molecules have stuck to the cold wall of
the cold trap.
11.10. PROJECTS 353
You must write a MATLAB script M-file that does the following:
(a) Prompt the user for:
i. Chamber height and width
ii. Connecting pipe height and width.
The pipe height must be less than or equal to the chamber height and greater
than 0.
iii. The number of molecules to simulate.
(b) Display the initial geometry as in first figure.
(c) Place the molecules in the left chamber and display the initial configuration as in
the second figure.
(d) Execute the time steps until all the molecules stick to the right most wall. Display
the final configuration as in fourth figure as well as the number of time-steps it
took to do the simulation.
Some hints:
When testing your code, use geometries with just a few cells for height and width
and just a few molecules. This will allow the simulations to complete quickly and
will test the more subtle parts of the code, the wall collisions and the action of
sticking to the cold wall.
When testing your code, make lots of use of visual output. Put in some graph-
ical output for some or all of the time-steps with a pause statement following
the graphics instruction. For example, the third figure shows some intermediate
graphical output. This is a very valuable way of debugging the operation of your
code.
You may need the following MATLAB function in your code (it is not mentioned
in the book!) to place the molecules randomly at the start. Using help uint32:
Note that the magnitude of the velocity, sqrt(vx^2 + vy^2) must be much less than
the speed of light, 3.0e8 m/s, for the equations described below to work sensibly. So,
make sure that the input speed is less than 3.0e6. The user should be prompted
repeatedly for inputs until sensible inputs are provided.
The script M-file will also execute a loop over all the timesteps in the evolution, and
provide final graphical output. Examples of the program output will be provided below.
X
N
Gmj (yi yj )
ayi =
i6=j [(xi xj )2 + (yi yj )2 ]3/2
where G is the gravitational constant (6.673 1011 nt-m2 /kg2 ). Note that the sum
PN
i6=j excludes the ith object, as an object (being point-like) does not exert any grav-
itational force on itself.
X
N
Gmj (xi (t) xj (t))
axi (t) =
i6=j [(xi (t) xj (t))2 + (yi (t) yj (t))2 ]3/2
X
N
Gmj (yi (t) yj (t))
ayi (t) =
i6=j [(xi (t) xj (t))2 + (yi (t) yj (t))2 ]3/2
(c) Estimate the positions and velocities at the end of the timestep assuming constant
acceleration.
1
xi (t + t) = xi (t) + vx,i (t)t + ax,i(t)(t)2
2
1
yi (t + t) = yi(t) + vy,i (t)t + ay,i (t)(t)2
2
vx,i (t + t) = vx,i(t) + ax,it
vy,i (t + t) = vx,i(t) + ay,i t
Here is an example of the Earth and Moon executing one orbit around the Sun. In
this case, I used a timestep of 3600 seconds and 365.25 24 timesteps.
11.10. PROJECTS 357
x 10
5 Wobble of the Suns center of mass
5
1
yaxis (m)
5
0 1 2 3 4 5 6 7 8 9 10
xaxis (m) 5
x 10
Figure 11.13: This is the wobble of the center of mass of the Sun.
358 CHAPTER 11. PROGRAMMING IN MATLAB
11
x 10
Earths orbit
2
1.5
0.5
yaxis (m)
0.5
1.5
2
2 1.5 1 0.5 0 0.5 1 1.5 2
xaxis (m) 11
x 10
10
x 10
Earth and moon together
7
6.5
5.5
yaxis (m)
4.5
3.5
2.5
1.2 1.25 1.3 1.35 1.4 1.45 1.5 1.55 1.6 1.65
xaxis (m) 11
x 10
Figure 11.15: This is part of the combined orbit of the Earth and the moon.
360 CHAPTER 11. PROGRAMMING IN MATLAB
8. Re-Mastermind
You will write MATLAB code, a simpler version of the Mastermind program of Chapter
8, one in which you, the user, try to guess the 4 hidden numbers.
You already know the rules of the game. Only, in the case, to make things simpler, the
uncovered numbers are represented by 0s rather than ?s. (Mixing characters and
numbers in MATLAB is a bit of a pain.)
And, the game continues until you either quit, or win. Pretty simple, huh?
Hints:
Confused? Try:
>> help rand
>> help floor
How can you input 4 numbers at once?
guess = input(Input your guess (1 <= [a,b,c,d] <= 9), [0,0,0,0] to quit: );
The above line prompts the user for input (See next page.) and the user can type
in the elements of a row vector.
Confused? Try:
>> help input
>> MasterMind
Input your guess (1 <= [a,b,c,d] <= 9), [0,0,0,0] to quit: [1,1,1,1]
uncovered =
0 0 0 0
board =
1 1 1 1
Input your guess (1 <= [a,b,c,d] <= 9), [0,0,0,0] to quit: [2,2,2,2]
uncovered =
0 0 2 0
board =
1 1 1 1
2 2 2 2
Input your guess (1 <= [a,b,c,d] <= 9), [0,0,0,0] to quit: [3,3,2,3]
uncovered =
0 0 2 0
board =
1 1 1 1
2 2 2 2
3 3 2 3
Input your guess (1 <= [a,b,c,d] <= 9), [0,0,0,0] to quit: [4,4,2,4]
uncovered =
0 0 2 0
board =
1 1 1 1
2 2 2 2
3 3 2 3
4 4 2 4
Input your guess (1 <= [a,b,c,d] <= 9), [0,0,0,0] to quit: [5,5,2,5]
uncovered =
0 5 2 0
board =
1 1 1 1
2 2 2 2
3 3 2 3
4 4 2 4
5 5 2 5
Input your guess (1 <= [a,b,c,d] <= 9), [0,0,0,0] to quit: [6,5,2,6]
uncovered =
0 5 2 6
board =
1 1 1 1
2 2 2 2
3 3 2 3
4 4 2 4
5 5 2 5
6 5 2 6
Input your guess (1 <= [a,b,c,d] <= 9), [0,0,0,0] to quit: [7,5,2,6]
uncovered =
7 5 2 6
board =
1 1 1 1
2 2 2 2
3 3 2 3
4 4 2 4
5 5 2 5
6 5 2 6
7 5 2 6
ans =
You win!
362 CHAPTER 11. PROGRAMMING IN MATLAB
In the US alone, there are 1.4 million new cancer patients each year.
Half of these will get treated with radiation. Cancer treatment using radiation is
called radiotherapy.
About 20% of those who are treated will die unnecessarily, even though cancer
was well localized. The radiation treatments were not effective enough to cure
them. If you do the math, thats 140,000 people per year in the US, about 50%
more people than live in Ann Arbor!
So, if you can make radiotherapy just 1% better, you will save 1,400 people per
year.
(a) Make a model of a cross section of the human body 3040 cm that is represented
by a 30 row by 40 column array called body. This array will represent the energy
deposited in the body by the radiation beams.
Rows = 30; Cols = 40; body = zeros(Rows, Cols);
(b) Make a working array that pads an extra row or column on the exterior of body.
This accounts for the outside. A(2:Rows + 1,2:Cols + 1) = body;
A(1,:) = 0; A(:,1) = 0; A(Rows + 2, :) = 0; A(:,Cols + 2) = 0;
(c) The tumor is a 44 cm square in the center of the body. Use pcolor and plot
to show the body and the outline of the tumor before the radiation is present.
Heres a hint:
show = A(2:Rows + 2,2:Cols + 2); %Handles off by one quirk in pcolor
%Some code to scale show so that its maximum value is 1.
%Hint: help max
11.10. PROJECTS 363
hold on
pcolor(0:Cols,0:Rows,show)
shading flat
plot(...you figure out the arguments...)
30
25
20
15
10
0
0 5 10 15 20 25 30 35 40
(d) Give the user of the program the capability of putting up to 4 beams on the
patient from the outside, one from the top, one from the bottom, one from the
left and one from the right. For example...
>> TreatCancer
Place beam top to bottom? (0 = no, 1 = yes) 1
Place beam bottom to top? (0 = no, 1 = yes) 1
Place beam left to right? (0 = no, 1 = yes) 1
Place beam right to left? (0 = no, 1 = yes) 1
2
This is much prettier in color!
364 CHAPTER 11. PROGRAMMING IN MATLAB
30
25
20
15
10
0
0 5 10 15 20 25 30 35 40
The beams decay (or attenuate) exponentially from the surface with a decay
constant of 15 cm. So, if a surface tile has energy energy value 1, at depth i,
where i represents the depth in centimeters, the value should be exp(-i/15).
Note that the beams should cover the entire extent of the tumor.
(e) If that was the whole story, cancer would be beaten! Unfortunately, radiation
spreads, the tumor does not get a full dose and the healthy tissue can get damaged.
A simple model of this spreading is to repeatedly average the energy value as
follows:
Perform this averaging 5 times (perform the operation on the array and then
repeat the process 4 more times) to produce a result that looks like the following
figure.
30
25
20
15
10
0
0 5 10 15 20 25 30 35 40
Open ended questions. (Optional.) Solve these and collect numerous Nobel prizes for
medicine and physics!
Model a real 3-dimensional person rather than the simple geometry above.
366 CHAPTER 11. PROGRAMMING IN MATLAB
Can you optimize the treatment by using more beams? (The answer is yes. The
difficulty is in finding the optimum configuration.)
What is the best decay constant to use? (This is related to the energy of the
beam.)
Develop the radiation physics to make the above calculation resemble reality.
Design a better radiation machine that will deliver better beams for radiotherapy.
Get this calculation done in 5 minutes or less!
Find out the real reason why radiation kills cells.
Find out what some radiation is good for you (far in excess of natural radiation
exposure). This is called radiation hormesis.
What role does radiation damage play in the development of cancers. This is
called oncogenesis.
Chapter 12
Graphics
x = linspace(-pi,pi,1000);
5
y = (x.^2).*sin(20*x) + x;
0
plot(x,y)
pause % Use a "pause" statement to stop 5
15
4 3 2 1 0 1 2 3 4
% Choose from:
% b: blue
% g: green
% r: red
% c: cyan
% m: magenta
% y: yellow
% k: black
% w: white
367
368 CHAPTER 12. GRAPHICS
15
plot(x,y,b) % blue 10
10
15
4 3 2 1 0 1 2 3 4
15
plot(x,y,g) % green 10
10
15
4 3 2 1 0 1 2 3 4
15
plot(x,y,r) % red 10
10
15
4 3 2 1 0 1 2 3 4
15
plot(x,y,c) % cyan 10
10
15
4 3 2 1 0 1 2 3 4
12.1. TWO DIMENSIONAL PLOTS 369
15
plot(x,y,m) % magenta 10
10
15
4 3 2 1 0 1 2 3 4
15
plot(x,y,y) % yellow 10
10
15
4 3 2 1 0 1 2 3 4
15
plot(x,y,k) % black 10
10
15
4 3 2 1 0 1 2 3 4
15
plot(x,y,w) % white 10
% White!!!!!
5
10
15
4 3 2 1 0 1 2 3 4
370 CHAPTER 12. GRAPHICS
plot(x,y,w) % white
title(Plotting white on white is dumb!) 5
10
15
4 3 2 1 0 1 2 3 4
% Axis labels
plot(x,y,k) 10
title(... 0
10
15
4 3 2 1 0 1 2 3 4
This is the xaxis
0.9
0.7
v = exp(-u.^2); 0.5
plot(u,v) 0.4
0.2
0.1
0
3 2 1 0 1 2 3
12.1. TWO DIMENSIONAL PLOTS 371
plot(u,v,k:) 0.9
0.8
0.7
0.6
0.5
0.4
0.3
0.2
0.1
0
3 2 1 0 1 2 3
plot(u,v,g-.) 0.9
0.8
0.7
0.6
0.5
0.4
0.3
0.2
0.1
0
3 2 1 0 1 2 3
plot(u,v,r--) 0.9
0.8
0.7
0.6
0.5
0.4
0.3
0.2
0.1
0
372 CHAPTER 12. GRAPHICS
1
plot(u,v,b-) 0.9
0.8
0.7
0.6
0.5
0.4
0.3
0.2
0.1
0
3 2 1 0 1 2 3
s = linspace(0.01, 6, 20);
3
t = log(gamma(s));
plot(s,t)
y
2
title(...
\fontsize{20}The log\Gamma(x) function) 1
xlabel(\fontsize{20}x)
ylabel(\fontsize{20}y) 0
1
0 1 2 3 4 5 6
x
plot(s,t,k:.)
4
1
0 1 2 3 4 5 6
5
plot(s,t,g-.o)
4
1
0 1 2 3 4 5 6
5
plot(s,t,r--x)
4
1
0 1 2 3 4 5 6
374 CHAPTER 12. GRAPHICS
5
plot(s,t,b-+)
4
1
0 1 2 3 4 5 6
plot(s,t,k:*)
4
1
0 1 2 3 4 5 6
plot(s,t,g-.S)
4
1
0 1 2 3 4 5 6
12.1. TWO DIMENSIONAL PLOTS 375
5
plot(s,t,r--d)
4
1
0 1 2 3 4 5 6
plot(s,t,b-V)
4
1
0 1 2 3 4 5 6
plot(s,t,k:^)
4
1
0 1 2 3 4 5 6
376 CHAPTER 12. GRAPHICS
plot(s,t,g>)
4
1
0 1 2 3 4 5 6
plot(s,t,r<)
4
1
0 1 2 3 4 5 6
plot(s,t,bp)
4
1
0 1 2 3 4 5 6
12.1. TWO DIMENSIONAL PLOTS 377
5
plot(s,t,kh)
4
1
0 1 2 3 4 5 6
plot(x,f0,k-,x,f1,k:,x,f2,k-.*,x,f3,k--o)
title(\fontsize{20}Plotting more than one thingPlotting
on the more same
than oneplot)
thing on the same plot
xlabel(\fontsize{20}x) 1
P0
P1
P2
ylabel(\fontsize{20}y) 0.8
P3
legend(P0,P1,P2,P3) 0.2
y
0.2
0.4
0.6
0.8
1
1 0.8 0.6 0.4 0.2 0 0.2 0.4 0.6 0.8 1
x
378 CHAPTER 12. GRAPHICS
P0
1 P1
P2
P3
0.8
plot(x,f0,k-) 0.2
plot(x,f1,k:) 0
plot(x,f2,k-.*) 0.2
0.4
plot(x,f3,k--o)
0.6
axis([-1,1,-1,1.1]) %[xmin,xmax,ymin,xmax] 0.8
legend(P0,P1,P2,P3) 1
1 0.8 0.6 0.4 0.2 0 0.2 0.4 0.6 0.8 1
P0
1 P1
P2
P3
0.8
0.2
g(2,1:length(x)) = f1;
0
g(3,1:length(x)) = f2; 0.2
plot(x,g) 0.6
legend(P0,P1,P2,P3) 1
1 0.8 0.6 0.4 0.2 0 0.2 0.4 0.6 0.8 1
12.1.8 Subplots
1.5 0.5
1 0
0.5 0.5
0 1
1 0.5 0 0.5 1 1 0.5 0 0.5 1
Plot 3 Plot 4
1
1
0.5
0.5
0
0.5
0.5 1
1 0.5 0 0.5 1 1 0.5 0 0.5 1
12.2. THREE DIMENSIONAL GRAPHICS 379
30
25
% Example using plot3
20
clear all
15
t = linspace(0, 10*pi, 1000); 10
plot3(sin(t),cos(t),t) 5
0
1
0.5 1
0.5
0
0
0.5
0.5
1 1
% Mesh plots
0.5
[x,y,z] = sphere(30); 0
mesh(x,y,z)
0.5
1
1
0.5 1
0.5
0
0
0.5
0.5
1 1
0.5
1
1
0.5 1
0.5
0
0
0.5
0.5
1 1
380 CHAPTER 12. GRAPHICS
1
0.5
1
1
0.5 1
0.5
0
0
0.5
0.5
1 1
0.5
1
1
0.5 1
0.5
0
0
0.5
0.5
1 1
0.5
1
1
0.5 1
0.5
0
0
0.5
0.5
1 1
12.2. THREE DIMENSIONAL GRAPHICS 381
xlabel(\fontsize{20}x-axis) 0.5
0.5
1
1
0.5 1
0.5
0
0
0.5
0.5
1 1
xaxis
ylabel(\fontsize{20}y-axis) 0.5
0.5
1
1
0.5 1
0.5
0
0
0.5
0.5
1 1
yaxis xaxis
% Provide a title 1
0.5
1
1
0.5 1
0.5
0
0
0.5
0.5
1 1
yaxis xaxis
382 CHAPTER 12. GRAPHICS
[x,y,z] = peaks(30); 5
6
subplot(1,2,1) 0
2
0
meshc(x,y,z),title(\fontsize{20}meshc) 2
subplot(1,2,2) 5
4
6
meshz(x,y,z),title(\fontsize{20}meshz) 10 8
4 4
2 4 2 4
2 2
0 0
0 0
2 2
2 2
4 4 4 4
10
4
12.2.5 Surface plots using surf 2
[x,y,z] = peaks(30); 4
6
surf(x,y,z) 8
3
title(\fontsize{20}Example using surf) 2
3
1 2
0 1
1 0
1
2 2
3 3
8
3
2
3
1 2
0 1
1 0
1
2 2
3 3
12.2. THREE DIMENSIONAL GRAPHICS Using shading interp 383
title(... 8
6
\fontsize{20}Using shading interp) 4
8
3
2
3
1 2
0 1
1 0
1
2 2
3 3
10
3
2
3
1 2
0 1
1 0
1
2 2
3 3
shading interp 8
6
colormap gray 4
8
3
2
3
1 2
0 1
1 0
1
2 2
3 3
384 CHAPTER 12. GRAPHICS
2
[x,y,z] = peaks(30);
contour(x,y,z,20) 1
3
3 2 1 0 1 2 3
2
colorbar % Show the colorbar 4
1
2
2
4
3
3 2 1 0 1 2 3
contour3(x,y,z,20) 8
grid off 2
6
3
2
3
1 2
0 1
1 0
1
2 2
3 3
6
2
pcolor(x,y,z) 1
2 4
6
3
3 2 1 0 1 2 3
with shading interp
12.2. THREE DIMENSIONAL GRAPHICS 3 385 8
6
2
0
0
1
2
2 4
6
3
3 2 1 0 1 2 3
contourf(x,y,z,12) 1
2
4
2
6
3
3 2 1 0 1 2 3
2.46
2 4.69 5.8
6.91
C = contour(x,y,z,12); 1.98
0.24
1.35
clabel(C) 0
0.872
2.46
0.24
3.57
title(... 1
2.46
5.32
4.21
2
0.872 3.1
3
3 2 1 0 1 2 3
386 CHAPTER 12. GRAPHICS
Chapter 13
Miscellaneous topics
This module gives some review on MATLABs implementation of for loops mostly by way
of example.
The general syntax of a for loop is
for k = vectorOrColumnList
% MATLAB statements
end
There are several ways of stepping through the elements of a row vector.
Example (Need vector value but not index):
The most common usage is C++-like syntax
%File: fex1.m
% For loop requiring vector value but not the index
for k = 1:3
fprintf(k = %g\n,k)
end
% Prints
k = 1
k = 2
k = 3
387
388 CHAPTER 13. MISCELLANEOUS TOPICS
or
%File: fex1a.m
% For loop requiring vector value but not the index
for k = 1:2:8
fprintf(k = %g\n,k)
end
% Prints
k = 1
k = 3
k = 5
k = 7
or
%File: fex1b.m
% For loop requiring vector value but not the index
for x = 1.0:-0.1:0.0
fprintf(x = %g\n,x)
end
% Prints
x = 1
x = 0.9
x = 0.8
x = 0.7
x = 0.6
x = 0.5
x = 0.4
x = 0.3
x = 0.2
x = 0.1
x = 0
or
%File: fex1c.m
% For loop requiring vector value but not the index
theta = linspace(0,90,3);
for thetai = theta
fprintf(theta = %g\n,thetai)
end
% Prints
13.1. PITFALL REVIEW 389
theta = 0
theta = 45
theta = 90
%File: fex2.m
% For loop requiring vector value and the index
v = linspace(0,250,3);
for i = 1:length(v)
fprintf(velocity(%g) = %g\n,i,v(i))
end
% Prints
velocity(1) = 0
velocity(2) = 125
velocity(3) = 250
%File: fex3.m
% Nested for loops
theta = linspace(0,90,2);
v = linspace(0,250,2);
for thetai = theta
fprintf(theta = %g\n,thetai)
for i = 1:length(v)
fprintf(velocity(%g) = %g\n,i,v(i))
end
end
% Prints
theta = 0
velocity(1) = 0
velocity(2) = 250
theta = 90
velocity(1) = 0
velocity(2) = 250
%File: fex4.m
% For loop where the index is a column vector
390 CHAPTER 13. MISCELLANEOUS TOPICS
a = [1 2 3
4 5 6];
[rows,columns] = size(a);
fprintf(a is a %g x %g matrix\n,rows,columns)
for b = a
disp(b);
disp(-------)
end
% Prints
a is a 2 x 3 matrix
1
4
-------
2
5
-------
3
6
-------
Note in this example that b is a new column vector on each iteration of the loop.
Some detail is given in Chapter 13 of Austin and Chancogne. However, the definitive ref-
erence for this course is given in the Chapter 11 that was handed out and is on the web.
This lecture gives some review on MATLABs implementation of functions mostly by way
of example.
Recall:
The general syntax of the function definition is to have a separate file called functionName.m
that has the following form:
[out1,out2,...,outN] = functionName(in1,in2,...inM)
Heres a function called noEvil.m that does nothing except printing something silly:
function noEvil
%NOEVIL noEvil is a function that does nothing
%
% ENG101 class example
%File: noEvil.m
disp(See no evil)
disp(Hear no evil)
disp(Do no evil)
disp(A function that does absolutely nothing)
function a2 = square(a)
%SQUARE square is a function that squares an argument
%
% It can accept scalars, vectors or matrices
%
% ENG101 class example
%File: square.m
a2 = a.^2;
392 CHAPTER 13. MISCELLANEOUS TOPICS
and some examples of its use on a scalar, a vector, a matrix and the element of a matrix:
>> square(2)
ans = 4
>> y = linspace(0,10,11)
y = 0 1 2 3 4 5 6 7 8 9 10
>> square(y)
ans = 0 1 4 9 16 25 36 49 64 81 100
>> x = round(10*rand(4))
x = 5 10 3 2
2 7 4 8
6 4 9 6
3 7 7 1
>> square(x)
ans = 25 100 9 4
4 49 16 64
36 16 81 36
9 49 49 1
>> z = square(x(2,2))
z = 49
%File: squareCube.m
a2 = a.^2;
a3 = a.^3;
>> squareCube(2)
ans = 4
>> [u,v] = squareCube(2)
u = 4
v = 8
>> y = linspace(0,10,11)
y = 0 1 2 3 4 5 6 7 8 9 10
>> squareCube(y)
ans = 0 1 4 9 16 25 36 49 64 81 100
>> [u,v] = squareCube(y)
u = 0 1 4 9 16 25 36 49 64 81 100
v = 0 1 8 27 64 125 216 343 512 729 1000
>> x = round(10*rand(4))
x = 10 9 8 9
2 8 4 7
6 5 6 2
5 0 8 4
>> squareCube(x)
ans = 100 81 64 81
4 64 16 49
36 25 36 4
25 0 64 16
>> [u,v] = squareCube(x)
u = 100 81 64 81
4 64 16 49
36 25 36 4
25 0 64 16
v = 1000 729 512 729
8 512 64 343
216 125 216 8
125 0 512 64
394 CHAPTER 13. MISCELLANEOUS TOPICS
Note that if you want to employ all the outputs you have to assign them, else only the
first output is displayed. These functions work on scalars, vectors, matrices and elements of
matrices.
Subordinate functions
%File: squareCallsCube.m
a2 = a.^2;
a3 = cube(a);
return
function c = cube(b)
c = b.^3;
squareCallsCube.m works the same way as if you had called squareCube.m. However, the
function cube.m is only known to the function squareCallsCube.m.
>> cube(a)
??? Undefined function or variable cube.
>>
13.2. THE MATLAB WAY 395
for i = 2:N-1
for j = 2:N-1
T(i,j) = 0.25*(oldT(i-1,j) + oldT(i+1,j) + oldT(i,j-1) + oldT(i,j+1));
end
end
Here is a faster solution obtained by using the intrinsic matrix operations of MATLAB. The
essential change is made by converting the for loops to
and changing them to
This will be demonstrated in lecture on a related problem. The speedup is highly dependent
on computer architecture. On the laptop the typical speedup is a factor of only about 2 for
a 50 by 50 array of temperature. On a high-end workstation, Ive obtained as high as 30
times faster.
Lets consider another trajectory problem that we will solve using the stepping method.
Consider taking an object at some height, y0 and dropping it with zero velocity, v0 = 0.
396 CHAPTER 13. MISCELLANEOUS TOPICS
This is a one-dimensional problem and can be solved completely with equations. However,
we will execute a computer solution as a model for solving more complex problems, like
trajectories of baseballs. The air resistance on a baseball is very significant. If there were no
air resistance, the longest home runs (about 600 feet or so) would travel half a mile!
The acceleration on the object is:
a = Dv 2 G (13.1)
where D is the drag and G is the acceleration due to gravity.
We can solve this in a formal fashion as follows:
Z t Z t0
0
y(t) = y0 + v0 t + dt dt00 a[v(t00 )] (13.2)
0 0
In fact, even if a were dependent on position y and time t we could write a formal solution
as: Z t Z t0
0
y(t) = y0 + v0 t + dt dt00 a[y(t00 ), v(t00 ), t00 ] (13.3)
0 0
But, this is a formal solution only and does not lead to any practical answers, only methods
of attack on this problem.
One such attack on the problem is to divide the integral above over a set of time interval t
and set up an iterative equation as follows.
Z ti1 +t Z t0
0
yi = yi1 + vi1 t + dt dt00 a[y(t00 ), v(t00 ), t00 ] (13.4)
ti1 ti1
which is still exact. However, if we make the approximation that the acceleration is constant
over the step, that is
we get
1
yi yi1 + vi1 t + ai [y(ti1), v(ti1 ), ti1 ]t2 (13.6)
2
and an algorithm that we can program:
2. Initialize a counter i = 1.
Note that two-dimensional problems are not really more complicated. There would just be
more variables to carry around.
Now the central question arises.
How small should I make t?????
The answer to THIS question is the art of computer programming and lies at the heart of the
general field of Numerical Methods. The field of Numerical Methods is also concerned
with developing better and faster techniques for solving problems than by the brute force
method outlined above. However, for this problem, we can more or less guarantee that our
results are good if the acceleration changes very little over a time step, namely
da
t a (13.7)
dt
At this point, lets simplify the discussion and consider just our problem. If we apply the
above condition to the problem we get
1
t (13.8)
2Dv
Does this make sense? It does! If there is no drag, D = 0, and we can make t anything we
like! This is because with no drag there is constant acceleration and we dont have to make
the steps small to get an accurate solution! (We have to be careful that we do not violate
our stopping criterion, however. More on this later.)
What if the v is small? In this case we can set t to be large because the drag is not affecting
the motion very much. If D and/or v are large enough such that Dv is large, we had better
use small time steps because drag forces are strongly affecting the trajectory.
How do we know how to set t for our problem? The greater the velocity, the greater care
we have to take by setting smaller time steps. The greatest velocity we can reach with our
problem is called the terminal velocity. This is when the drag force and the acceleration
force exactly balance each other and there is no net acceleration. For free fall with air
resistance, this velocity is
s
G
vT = (13.9)
D
For our baseball the terminal velocity is something like 129 ft/s.
398 CHAPTER 13. MISCELLANEOUS TOPICS
This is the upper limit of the velocity and so we are conservative by saying that
1
t (13.10)
2 DG
or t 2.
How much smaller than 2 shall we make t? Usually as small as you can get away with!
If you want the error to be of the order of 1% or less, you should set it to something below
0.02 seconds. At least we have some indication from a simple analysis.
Now we implement the algorithm with MATLAB coding. Here is what the essential working
part of the algorithm would look like:
Heres what the complete code would look like. It gives some example of organization and
plotting:
%File: drag.m
clear % Clears variables
echo off % Turns off echo
clc % Clears the screen
while dT > 0
end
while (y > 0)
a = D*v^2 - G; % Acceleration at beginning of step
y = y + v*dT + 0.5*a*dT^2; % Position at end of the step
v = v + a*dT; % Velocity at end of the step
% Plotting arrays
index = index + 1;
Y(index) = y;
V(index) = v;
T(index) = T(index - 1) + dT;
end
subplot(1,2,1)
zoom on
hold on
plot(T,Y,-)
title(y as a function of t)
xlabel(time (s))
ylabel(height (ft))
subplot(1,2,2)
zoom on
hold on
plot(T,V,-)
title(v as a function of t)
xlabel(time (s))
ylabel(height (ft/s))
end
When we run this code, as demonstrated in class, we see that the trajectory always over-
400 CHAPTER 13. MISCELLANEOUS TOPICS
shoots. We always end up with a negative y at the end. We have to make t very small to
get the final position close to zero. We can fix this problem relatively easily.
What we can do is check to see if the t we are about to use will cause an overshoot and if
it will, to truncate it accordingly.
How do we truncate it? Recall that we are assuming that the acceleration over the course
of the step is constant. If that is so, we can calculate the t required to bring it exactly to
zero. It must satisfy the quadratic equation:
1
0 = yi1 + vi1 t + ai [y(ti1 ), v(ti1 ), ti1 ]t2 (13.11)
2
You can solve this with the quadratic equation and convince yourselves that the solution is:
Here is the new working part of the algorithm incorporating this idea. (See the example
code drag0.m.)
while (y > 0)
a = D*v^2 - G; % Acceleration at beginning of step
yTest = y + v*dT + 0.5*a*dT^2; % Position at end of the step
if yTest < 0
% Handle the overshoot
dT = -(v + sqrt(v^2 - 2*y*a))/a;
y = 0;
else
y = yTest;
end
v = v + a*dT; % Velocity at end of the step
end
So now we have a trajectory that always ends in the right place and an algorithm that is
guaranteed to get us close to the right answer. We are now a long way towards solving more
complicated problems, like two-dimensional trajectories of baseballs.
This is the problem of positive and negative ions created somehow (like a pulse of radiation)
in a gas drifting in opposite directions under the influence of a constant electric field. Run
13.3. SELECTED APPLICATIONS 401
the following code called ion.m that resides in the classcodes area. Note how the leading
edge is more populated with ions than the trailing edges since the longer an ion spends in
the vicinity of ions of opposite charge the greater the chance that it will recombine and
neutralize.
%File: ion.m
clear all
echo off
clc
NSteps = 100;
NIon = 2000;
for i = 1:NIon
x1(i) = rand; y1(i) = rand;
x2(i) = rand; y2(i) = rand;
end
plot(x1,y1,b*,x2,y2,r*)
axis([-1 2 0 1])
axis off
title(\fontsize{20}Initial configuration)
pause
end
402 CHAPTER 13. MISCELLANEOUS TOPICS
plot(x1,y1,b*,x2,y2,r*)
axis([-1 2 0 1])
axis off
title(\fontsize{20}\leftarrow +ions | -ions\rightarrow)
pause(0.01)
end
Constant electric fields as employed in the problem above are really fictional. In this sim-
ulation we mock-up a realistic electric field situation. Run the following code called phi.m
that resides in the classcodes area. Note how strong the electric field is near the insulator.
(It helps to have come to class get the full description of this problem!)
%File: phi.m
clear all
echo off
clc
V = zeros(N);
V(1,N/2:N) = 1000;
V(N,N/2:N) = 1000;
V(:,N) = 1000;
oldV = V;
change = 10;
tic
counter = 0;
while(change > delta)
V(2:N-1,2:N-1) = ...
0.25*( ...
V(1:N-2,2:N-1) + V(3:N,2:N-1) + V(2:N-1,1:N-2) + V(2:N-1,3:N) ...
);
difference = abs(V - oldV);
13.3. SELECTED APPLICATIONS 403
change = sum(sum(difference))/(N^2);
counter = counter + 1;
if mod(counter,100) == 0
fprintf(Interation %g, average change = %g\n,counter,change)
end
oldV = V;
end
toc
pcolor(1:N,1:N,V);
shading interp;
xlabel(\fontsize{20}X-grid);
ylabel(\fontsize{20}Y-grid);
title(\fontsize{20}Voltage in the chamber);
pause
figure
[Ex,Ey] = gradient(V);
E = sqrt(Ex.^2 + Ey.^2);
warning off
pcolor(1:N,1:N,log(E));
shading interp;
xlabel(\fontsize{20}X-grid);
ylabel(\fontsize{20}Y-grid);
title(...
\fontsize{20}Mag. of electric field in the chamber);
pause
figure
surf(1:N,1:N,log(E));
shading interp;
xlabel(\fontsize{20}X-grid);
ylabel(\fontsize{20}Y-grid);
title(...
\fontsize{20}Mag. of electric field in the chamber);
404 CHAPTER 13. MISCELLANEOUS TOPICS
2. Convert it to MATLAB
6. When the MATLAB version is acceptable, re-code the algorithm in C++ starting with
the MATLAB code.
7. Run the same set of test problems using the C++ code.
8. Make sure that the C++ results and the MATLAB results of test problems are iden-
tical.
9. When the C++ code passes the tests, increase array size or introduce sufficient com-
plexity to solve the problem you really want to solve.
10. Have C++ write data arrays that MATLAB can read in an display, using MATLABs
excellent graphics capabilities.
The upshot is that both ways of doing it has its strengths and weaknesses. Why not use
both?
Chapter 14
Indent 3 spaces relative to the preceding for every new nesting level. Curly brackets
must always align vertically. Example,
int main(void)
{
int i = 0, k = 1;
if (i < k)
{ int temp = i;
i = k;
k = temp;
if (0 == k)
{ i = i*i;
k = -i;
}
}
return 0;
}
405
406 CHAPTER 14. PROGRAMMING STYLE GUIDE FOR C++
Variable and function names are in lowercase, terse but descriptive, enough information
conveyed within the programming context, with capital letters to start new words
internal to the identifier. Example,
numStuds = 211;
degToRad = 180/PI;
numberOfStudentsInTheENG101Setion200Class = 211;
conversionFactorForDegreesToRadians = 180/PI;
The first encouter with a variable merits a short comment unless the meaning is com-
pletely obvious. Example,
this_variable_name_is_difficult_to_type = 211;
cute_______________but_dumb = true;
Variable should be initialized near where they are first used and should only be defined
within the scope for which they are relevant. Examples,
There are spaces before and after the binary operators =, +, -, ==, !=, <, <=, >, >=, &&
and ||. Examples,
There are no spaces before and after the binary operators *, /, and %. There is no
space following the unary operators - and !. Examples,
No hardwired constants!
Bad example:
int a[10][10]
for (i = 0; i == 9; i = i + 1)
for (j = 0; j == 9; j = j + 1)
a[i][j] = 1;
Good example:
Functions should be small enough so that they fit on the screen. Thats about 30 lines
of code.
#include statements
Constants
Global variables
Functions, with own headers. Function prototypes are optional unless required by
ordering constraints.
/********************************************************************
Copyright (C): University of Michigan
Project: ENG101/200 - Class example
File: C++example.cpp
Purpose: Coding example to show code layout
Compiler: g++
Programmer: Alex Bielajew
Start Date: 01/18/01
*********************************************************************/
// CONSTANTS ********************************************************
// FUNCTIONS ********************************************************
/*********************************************************************
Purpose: Calculate the integral power of a float using the algorithm
of al-Kashi
Receives: "x" which is to be raised to the power "n"
Returns: a float, the result of x raised to the power n
*********************************************************************/
if (0 > n)
{ n = -n;
410 CHAPTER 14. PROGRAMMING STYLE GUIDE FOR C++
x = 1/x;
}
result = 1;
while(1 <= n)
{ if (0 == n % 2)
{ n = n/2;
x = x*x;
}
else
{ n = n - 1;
result = result*x;
}
}
return result;
}
411
int main(void)
/*********************************************************************
Purpose: To prompt the user for a float x and and int n and call a
function that computes x to the power of n
*********************************************************************/
result = pow(x,n);
cout << x << " to the power " << n << " = " << result << "\n";
return(0);
}
412 CHAPTER 14. PROGRAMMING STYLE GUIDE FOR C++
Chapter 15
413
414 CHAPTER 15. SYNTAX REFERENCE FOR BEGINNING C++
A Pseudocode is a way of expressing the actions and ordering to be taken place on a computer in an exact yet informal
way, without details or syntax of a particular computer language.
If/Else
if(logical expression 1) else ifs are optional
else if(logical expression 2) may ignore the {}, but for clarity it is better to keep them
{ STATEMENT BODY 2
else
{ STATEMENT BODY N
Loops
While
Do/While
For
} expression 2 is optional
Example Programs
CODE OUTPUT CODE OUTPUT
#include<iostream> 1 #include<iostream> 1
416 CHAPTER 15. SYNTAX REFERENCE FOR BEGINNING C++
#include<iostream>
using namespace std;
int main(void) i is 2. j is -2.
{ int i = 2,j = -2; i is 1. j is -1.
while(j <= i)
{ if(j < 0 )
{ cout << "i is " << i <<". "
<< "j is " << j << ".\n";
i = i - 1;
}
j = j + 1;
}
return 0;
}
Chapter 16
Addresses
The address of a variable is its location in memorytypically some number from between 0 and 232 1.
The piece of code {int i; cout << &i << "\n";} should be read as i is declared an int. Print the address of i in hexadecimal
format..
The function definition is written at the top of the C++ file outside of main or any other function. A function definition
must be given before any code that uses the function via a function call. Generic syntax:
The function call is made inside of main or another function. Generic syntax:
417
418 CHAPTER 16. SYNTAX REFERENCE FOR MORE ADVANCED C++
Function call by value means that the parameter list of the function definition contains values. Example:
Note:Copies of these values are made available to the function. These are lost when the function returns.
Function call by reference means that the parameter list of the function defnition contains addresses. Example:
Note: Functions called by reference can change the contents of the addresses that are made available to the
function in the reference list.
Vectors
Using vectors
#include <vector> // Must be included in the pre-processor area
Note: Vectors are a class defined in standard C++
for(i = 0; i < 10; i = i + 1){vectorName[i] = i + 1}; // for loop assigns all elements of vectorName
vectorName[9] = i; // The last (10th) element of vector vectorName is assigned the value of i
int arrayName[2][3] = {{1,2,3}}; // Initialize the first row of arrayName, rest to zero;
419
arrayName[1][1] = i; // The last 2nd row/2nd column element of array arrayName is assigned the value of i
Note: arrayName is the address of arrayName[0][0], that is, arrayName is the same as &arrayName[0][0]
Passing 2D arrays to functions Remember that an array name is the address of the start of the array
Note that that the column size (second index) must be known by the function!
Printing strings
Structures
are compound data types. Structures have to be: 1) defined, 2) declared, 3) initialized, 4) used.
Defining a structure
struct AgeAndHeight {int age; float height;}; // Structure tag AgeAndHeight with an int and a float;
Declaring a struct
struct AgeAndHeight Wilma = {26,65.5}; // Declares Wilma as an AgeAndHeight struct and initializes it
cout << "Wilmas height is: " << Wilma.height << endl; // Prints Wilmas height
Struct vectors
Struct arrays
Struct vectors and arrays are passed to functions in the same way as the standard variable types.
Recursion
Functions can call themselves. Factorial example:
int factorial(int n)
{ if (0 == n) return 1;
else return (n * factorial(n - 1));
}
421
422 CHAPTER 17. SYNTAX REFERENCE FOR MATLAB
MATLAB punctuation
. decimal point 325/100, 3.25 and .325e1 are all the same
... three or more decimal points at the end of a line cause
the following line to be a continuation
, comma is used to separate matrix subscripts and arguments
to functions, also used to separate statements in
multi-statement lines
; used inside brackets to indicate the ends of the rows of a
matrix, also used after an expression or statement
to suppress printing
% begins comments
Quote. ANY TEXT is a vector whose components are the
ASCII codes for the characters. A quote within the text is
indicated by two quotes. For example: Dont forget.
Assignment
Individual elements with a row can be delimited by a comma or
a space.
a = [1,2,3;4,5,6;7,8,9]
a = [1,2,3
4,5,6
7,8,9]
b = [1 2 3 4 5 6 ...
7 8 9 10]
Vector/Matrix operators
These are Vector and Matrix operators
+ addition
- subtraction
* multiplication
/ left division
\ right division
^ exponentiation
transpose
Point-by-point operators
These operate on matrix elements in point-wise fashion
.* point-wise multiplication
./ point-wise left division
.\ point-wise right division
.^ point-wise exponentiation
Logical operators
< less than
<= less than or equal
> greater than
425
Script M-files
Sequences of MATLAB commands can be stored in text files with the extension .m. The
commands can be executed with typing the name of the files (without the extension) or
through the file management tools provided by the Command Window menu.
% .
% .
% More description (optional)
% .
% .
% .
% First executable statement follows this line
.
.
.
% Valid executable MATLAB statements and comments
.
.
.
% Last line in functionName
Function call
[out1,out2,...,outN] = functionName(in1,in2,...inM)
Performance monitoring
tic,toc stopwatch timer functions
flops counts floating point operations
427
Formatting
format short Scaled fixed point format with 5 digits
format long Scaled fixed point format with 15 digits
format compact Suppress extra line-feeds
format loose Puts extra line-feeds in the output
for loops
for k = vectorOrColumnList
% MATLAB statements
end
while loops
while logicalExpression
% MATLAB statements
end
if/elseif/else construct
if logicalExpression1 % Mandatory
% MATLAB statements
elseif logicalExpression2 % Optional
% MATLAB statements
elseif logicalExpression3 % Optional
.
.
.
elseif logicalExpressionN % Optional
% MATLAB statements
else % Optional
% MATLAB statements
end % Mandatory
428 CHAPTER 17. SYNTAX REFERENCE FOR MATLAB
Plotting
contour Contour plot on a plane
contour3 3-D contour plot with displayed depth
mesh 3-D mesh surface
meshc Combination mesh/contour plot
meshz 3-D mesh with curtain
pcolor Pseudocolor (checkerboard) plot
plot Basic 2D plots
plot3 Plot lines and points in 3-D space
surf 3-D colored surface
surfc Combination surf/contour plot
surfl 3-D shaded surface with lighting
Plotting annotation
clabel Contour plot elevation labels
colorbar Display color bar (color scale
legend Graph legend
title Graph title
xlabel X-axis label
ylabel Y-axis label