Professional Documents
Culture Documents
Program Design
Chapter XV Topics
15.1 Introduction
15.1 Introduction
Who cares about step-wise refinement when you have no idea how to use a text
editor, save a program, or for that matter boot the computer. I have vivid memories
of attending a lecture on proper program design. It was the first lecture of the first
computer science course I took back in the Seventies. At the end of the lecture a
program assignment was handed to the students, to be turned in one week later. Not
one detail was given about using the computer. In other words, students marched to
the computer lab, their heads buzzing with program design terminology, and not a
clue how to log-on to the mainframe computer, or even write a program that would
compute the sum of two numbers.
This book has taken those experiences into account. Now that you know enough
about computer hardware and software, and you have a foundation knowledge of
one particular programming language, you are ready for some firm guidance in
proper program design.
With the popularity and availability of micro computers it is not unusual for students
to start any program by planting themselves behind a computer and hope that the
fingers on the keyboard will be manipulated by cosmic guidance... or at least the
guidance of a fellow student of your teacher.
Many times, neither a fellow student nor the teacher is available and cosmic
guidance has not always proven reliable with computer assignments. There comes a
time when the burden of solving the problem falls on YOU.
Keep in mind that there is no substitute for actual practice when you wish to acquire
problem solving skills, but this chapter hopes to give some directions that may be
useful. It is suggested that even the skilled programmers who have finished every
assignment ahead of time take the time to read this chapter.
It is difficult to justify program design principles when your programs are very
small. Frankly, it matters little how you write a short program. It is precisely with
In the short history of computer science sad chapters have already accumulated. A
suspension bridge in Idaho collapsed in heavy cross winds, killing many people.
The cause was traced to a faulty program used by construction engineers. Hospitals
have used sophisticated medical equipment with faulty programs that has resulted in
unnecessary injury or loss of lives to patients. At the same time correct or incorrect
programs mean huge losses or profits for the business world. The new Denver
International airport lost untold millions when the airport opened much later than
planned due to program problems in its luggage handling system. In the years
approaching 2000, programmers have been struggling to fix the headache of old
programs that cannot digest four digit years. In these old programs, both 1900 and
2000 is recorded as 00. The impact of this problem can be very profound in the
business world and companies have spent millions of dollars fixing old programs.
One of the biggest problems in fixing the old programs is poor program design that
makes the Y2K update both difficult to find and fix.
Even as a high school student you will find that proper program design principles
will make program writing simpler and quicker. Students who continue with the
second year course will especially need these principles as program assignments
grow in length and complexity.
What are the steps of program development? Ten textbooks may list ten different
sets of steps, but most of the popular textbooks will likely adhere closely to
statements that sound like the five steps listed below.
These steps will probably surprise you. The average student has the tendency to
start with step 3 and often wonders why the program has so many problems. Check
out these steps. Where have you been starting with your program assignments?
Let us be honest now. How often did you sit behind the computer and start typing in
the program immediately? Step 1 certainly gets skipped a lot. Are you one of
many students who does not even bother to read the specifications of the program
assignment? Well, do not feel alone. Many students are too impatient to read
specifications, even if it saves time on the long run. With this chapter let us start
writing programs correctly. We will start by explaining each step briefly and then
return and looks at the program development steps in considerable detail.
The first step in computer program development is ignored more than anything else.
Can a program expert with twenty years computer science experience write a
program that will play chess, unless such a person understands the game of chess?
Can somebody write a program which will multiply two matrices unless he or she
knows how to multiply matrices? You know the answer to these questions.
Therefore, before anything else happens, you need to understand the problem. This
is particularly important, since the real situation is often such that problem
originators are usually not programmers.
Create an Algorithm
At this stage you need to determine the programming language that you will use.
C++ may not always be the best solution. As you become a more experienced
programmer, you will be able to select from different languages for different
Even programs that are very well planned and developed properly require updating
and enhancing. Situations arise that were not considered in the early planning stages
and the actual process of interacting with a working copy of the program often
motivates improvement ideas.
In most cases a programmer does not originate the specifications for a program. If
he or she is a student in a computer science course, the program assignment will be
given by the class instructor, and in the business world it is usually the customer
who determines what needs to be programmed. Large programs are written by a
team of programmers who each have a specific assignment to complete. Even if you
write a program strictly for your own sake, you will need to start at this point. What
exactly is this point?
PROCESS
OUTPUT
How do you start if you have understood the problem? This is not always as easy as
it sounds, but before you even touch a key on the computer, solve the problem
yourself. In other words, act like the computer yourself. This simple piece of
instruction works very well. Your very first step in writing the payroll program
above is not to ponder about how to write this or that program segment. First, get
out some paper, write down some typical input data and proceed to process the data
until you get the required output.
Also keep in mind that if you are stumped at the starting point, then no amount of
computer-busy-work will help you out. Arno Penzias, famous computer scientist,
astronomer, and 1959 Nobel Prize winner, makes an interesting quote about such
stumped conditions.
The questions go on. Many computer science teachers avoid students’ program
specifications dilemmas. Teachers usually pass out a detailed program assignment
handbook at the start of the course or individual specifications prior to each required
program assignment.
You are happy with step ONE. You know the problem. You have acquired the
program specifications, and now you are ready to get down to some serious
business. What is next? Typing in the program on the computer? One may think
that this is the logical choice, if you watch the approach that many students use with
their assignments.
When you are writing short programs, this step seems totally useless. A program
which adds and subtracts two entered numbers does not require too much thought.
On the other hand if your assignment is to write a program that plays chess, then you
have a major problem on your hand. It is precisely with the larger, and more true-to-
life, kind of programs that hacking away at the computer - without much prior
thought - simply does not work. Who can write a chess program without a large
amount of planning?
The first approach is not very clever, but quite effective for small programs or
procedures. It consists of neatly writing down the exact steps that are performed in
solving a given problem. In many cases whether you are averaging a set of
numbers, computing somebody's net pay, or a similar short problem, you have the
algorithm in front of you. You solved the problem. Closely observing these steps
and writing them in a logical order will often yield a workable algorithm.
However, there are problems which are totally beyond such a method. No attempt is
made here to develop a chess program, but how would you develop an algorithm for
chess anyway? Where would you start?
The commonly accepted method in the computer science community is to use the
Top-Down-Design-and-Step-Wise-Refinements approach. Top-down means to
work from the top to the bottom. From general to specific. Step-wise refinements
indicate the levels in the design that refine the problem to greater detail at every step
"down" to the next, more detailed, level.
Let us apply this top-down approach to the chess program. Keep in mind this is
over-simplified, but you should understand the general idea of building a program
design from general to specific.
Write a
Chess Program
King King
Queen Queen
Rooks Rook
Bishops Bishop
Knights Knight
Pawns Pawn
The entire chess program is so mind-boggling that you cannot comprehend it all
together. With a top-down design you can refine each level to a step that is
manageable, such as teaching the computer to display a knight, or check if a queen is
moved properly, or display the 64 squares of the board. The main point is that you
develop your algorithm by starting at the top in a very general manner and determine
the main modules. This is the first level of refinement. A very rough refinement,
but at each level the algorithm becomes more and more specific. The changes from
one level to the next level are relatively small. These small step-wise refinements
are easier to manage than plunging in immediately to some small detail.
You should write your C++ programs in such a manner that the main function is like
looking at the first level of your top-down design algorithm, as is shown below, with
the main function of a chess program.
void main()
{
bool Finished;
This second step will also increase your computer lab efficiency. Students do not
always have access to a computer. Not every student has a computer at home, and
students who do have a computer at home do not necessarily have every opportunity
to use it. Parents are very strange, frequently they want to use the computer they
have paid for. In such situations you can take out some paper and start thinking
about designing your program. Remember the following:
After the program specifications are clear, make sure that you
can solve the problem yourself. Take sample input and go
through the steps required to process the desired output.
Algorithm Example
The algorithm example that follows computes the Greatest Common Factor (GCF)
of two integers. This algorithm can be used not only for writing a program, but also
for teaching a math class.
Step 4:
If the remainder is not 0 then Integer1 is now 108
Integer1 becomes Integer 2 and Integer2 is now 12
Integer2 becomes the remainder
Step 5:
Go to Step2:
Step 2:
Divide Integer1 by Integer2 and 108 / 12 = 9
compute the remainder. The remainder = 0
Step 3:
If the remainder equals 0, you are The remainder is 0
finished. The GCF is Integer2. You are finished and the
GCF = 12
You can take this GCF algorithm and give it to a younger brother or sister in
elementary school. It will help him or her with math homework that involves the
computation of Greatest Common Factors. There is another reason for this precise
step-by-step algorithm approach. Excuse me for saying this, but many people,
students included, think in a scattered fashion. By some brain process, which I do
not comprehend, many scattered thinkers do get desired results in their daily
routines. Unfortunately, the same approach applied to a computer program gets
scattered results. The computer lacks the subconscious intelligence that sorts out the
confusing thought process.
This chapter in general, and the top-down approach specifically, is very important in
procedural programming. Procedural programming emphasizes program design
with modules, which are implemented with functions in the C++ language. Very
soon you will be introduced to OOP (Object Oriented Programming). In OOP the
approach to program design is not exactly the same as it is in procedural
programming. This leaves authors of computer science books, which teach C++ and
OOP, with a problem. You can use the approach that students need to learn the
procedural, pre-oop programming style first. You can also plunge in and do
everything the OOP way right away or very early. There are merits in both
approaches. My biggest objection with the early OOP approach is that students
know very little about OOP before they are expected to understand program design
You will need to waste precious little time pondering which programming language
your newly designed algorithm should employ. This is a computer science book
titled, Exposure C++, and you are taking a course which is at this moment is
teaching you programming in C++.
However, the coding step does include deciding on the language to use. Little will
be said about that here. You need to gain more knowledge about the advantages and
disadvantages of various languages before you can decide on the best language for a
given application.
A confession needs to be made. So far the impression has been given that the
algorithm was created completely independent of any language choice. This is not
It may seem that efficiency means the execution speed of the program, but that is not
always the case. There are memory concerns, as well as program maintenance
(readability) that must be considered in the design of a program.
Efficiency Considerations
Execution Efficiency
Memory Efficiency
Program Maintenance Efficiency (Readability)
What these three steps specify is that it is not good enough that a program works.
Perhaps one of the most tiresome comments made by students is complaining about
points taken off for lack of efficiency, or styling by saying that "it works". That
philosophy was fine in the days of the 1 million dollar computers and the five-
thousand-dollar-a-year programmers. Today's hardware is relatively cheap, while
custom software costs a fortune to develop for businesses. Money is not spent on
software that merely works, but that also considers the three points above. Let us
take a look at each point in turn.
Execution Efficiency
Some years back - in the early eighties - the head football coach at Berkner High
School wanted a computer program to assist him in analyzing data. The coach had a
student who convinced his coach that he was great. Maybe not so great on the
football field, but absolutely terrific with computers. The enterprising student
The data processing package mentioned above did work correctly, but the execution
efficiency was horrible. Several poor decisions had been made in its development
stage. Two factors combined to cause the incredible slow-down. First the program
was written in interpretive BASIC. You should remember that interpretive
languages execute much slower than compiled languages. This happens especially
when nested loops are involved. The second factor was the choice of the Bubble
Sort for the sorting algorithm. You may not be familiar yet with many different
sorting routines, but the Bubble Sort is one of the slowest sorts available.
Execution efficiency is controlled by the language you use, and the algorithms you
create. It is assumed that little choice can be made about hardware. Do keep in
mind that some computers operate much faster than others. However, unless you
have unlimited financial resources, you will need to use the equipment that you own
or have to use at school or work. Regardless of the available hardware, strictly at the
coding level you can make a big difference by watching closely what you code.
Cramer's Rule is a method for solving equations with more than one unknown. It is
not important to understand the details of Cramer's Rule. The formula is shown in a
general form below. The main point being made is that every value computed
requires division by the same general determinant. The determinant is a value that
takes a considerable amount of computations, especially when the equations have
many unknowns. Solving equations with many unknowns is a very common
requirement in the engineering and business world. The general example shown
below is for three equations with three unknowns.
Cramer’s Rule
X Value
Determinant
Y Value
Determinant
General
Determinant
Z Value
Determinant
General
Determinant
In the illustration about Cramer's Rule the values of X, Y and Z are computed, and
in each case it is necessary to use the same general determinant. Many students
write this program using two separate formulas. This is fine, but what is not so fine
is when each formula includes the computation of the same general determinant.
Execution efficiency is increased considerably if the determinant is first computed,
ONE TIME, and then its value is used in the formulas that follow. The example
showed the required computations for three equations with three unknowns. In the
case where ten equations need to be solved with ten unknowns the same general
determinant will need to be computed ten times. In such a case the unnecessary
computations will make a very noticeable difference in execution speed.
Memory Efficiency
Every character in your program occupies memory space in the computer. Small,
simple programs are of little concern here, but the bigger programs will reach a point
where they will not function properly. Either the program needs to be condensed or
additional memory needs to be added. Usually, memory usage is unavoidable, but at
other times the program can be designed to save a considerable amount of memory.
This memory business is of no consequence with the program assignments that you
have completed so far. But it becomes very real when the programs become larger
in the future. You will find that memory gets gobbled up very rapidly. This is
especially true when your program uses graphics. For instance a modest VGA
graphics screen with 320 X 200 pixels is a total of 64,000 pixels. Each pixel is
stored as one byte and storing a graphics screen requires 64,000 bytes. Keep in
mind that we are only talking about a relatively low resolution of 320 X 200 pixels.
Many graphics screens use 800 X 600 or 1024 X 768 pixels.
Documentation will be addressed shortly, but keep in mind that you have some
decisions to make. Single-letter variables and totally undocumented programs take
less memory. However, as the next section explains, that may create an inefficiency
of a different type.
// PROG1501.CPP
#include <iostream.H>
#include <conio.h>
void main() {clrscr();int A,B,C,D;cout<<"Enter";
cin>>A;cout<<"Enter";cin>>B;do{C=A
%B;if(C==0)D=B;else{A=B;B=C;
}}while(C!=0);cout<<endl<<endl;cout<<D<<endl;getch();}
// PROG1502.CPP
/********************************************************************/
/* This program computes the Greatest Common Factor (GCF) of two */
/* entered integers. The method used was devised by Euclid over */
/* two thousands years ago, and today it is still one of the most */
/* efficient methods for finding the GCF. */
/********************************************************************/
#include <iostream.H>
#include <conio.h>
void main()
{
clrscr();
int Number1, Number2;
int Remainder;
To a large degree, styling is subjective and opinions vary considerably. You have
already seen many program examples in this book that demonstrate one particular
C++ style that is used by many people. It is by no means the only appropriate style
for writing a C++ program. There are many styles and some styles are more useful
for certain purposes. For instance, the GCF program will be shown again with a
different style that is popular because it reduces the number of indentations used in a
program, and the number of lines on the screen. This kind of style is popular for
large programs.
// PROG1502.CPP
//
// This program computes the Greatest Common Factor
(GCF) of two
// entered integers. The method used was devised by
Euclid over
// two thousands years ago, and today it is still one
of the most
// efficient methods for finding the GCF.
// This example uses a different program style.
void main() {
clrscr();
int Number1, Number2;
int Remainder;
int GCF;
cout << "Enter 1st number ===>> ";
cin >> Number1;
cout << "Enter 2nd number ===>> ";
cin >> Number2;
do {
Remainder = Number1 % Number2;
if (Remainder == 0)
GCF = Number2;
else {
Number1 = Number2;
Number2 = Remainder;
}
}while (Remainder != 0);
cout << endl << endl;
cout << "The greatest common factor is " << GCF <<
endl;
getch();
}
But proper consistent styling and self-documenting variable names are not sufficient
for maintenance efficiency. A program require documentation. Documentation is
not just a case of a single piece of paper explaining how to install the program. It is
not even a large, thick book, explaining every tiny detail of the program. Program
documentation is a combination of several items.
Program Documentation
The current emphasis is on more and more online documentation. Experience has
shown that program users are very reluctant to use their reference manuals. Clear,
well placed, online documentation is a major factor in making software packages
popular. Both the Macintosh computers and PCs with windows are designed to give
clear guidance to program users, as it is needed, in multiple pop-up windows.
Internal Documentation
The importance of self-documenting identifiers has been demonstrated earlier with
the condense GCF program. Program comments are comments contained within the
source code to explain variables, program segments and functions. Comments need
to be inserted - where necessary - to clear up confusion or to provide insight in the
logic of a certain function. Good internal documentation is critical in testing,
debugging and in future modification. However, only use comments if additional
information is provided. Do not add comments just to please your teacher.
External Documentation
External documentation usually falls into two categories: User manuals and
technical reference manuals. User manuals are written for the primary program
user, who frequently is not a very technical person, and has no interest in program
modification. The technical reference manual provides detailed information that is
Recognizing which one of the three errors occurs is the most important step in
debugging a troubled program. Remember, no matter how stumped you are by your
program’s uncooperative nature, you always should be able to state what type of
error your program has. I can assure you that your teacher will be very pleased if
you can say something like:
Excuse me Mrs. Hromcik, my program has a compile error that says I have an
unknown identifier, or something like Excuse me, Mr. Rosier, my program compiles
and executes, but the output does not make any sense at all.
Since the compiler specifically checks syntax errors, and it gives a syntax error
message, the error is also called a compile error. Your C++ compiler rapidly finds
any syntax errors, but you must accept the following three facts about any C++
compiler that you might be using.
Students usually have little difficulty with cryptic error messages. Even if a message
is totally logical, it is still overlooked in most cases. The real problem is that
students expect the error indicator to be at the error location. I have time, and time,
and time again seen students in total puzzlement. The error message was very
accommodating stating: Semi-colon expected.
My hardworking, motivated students would look and look at the highlighted line
with the error message. Everything looked just fine and all required semi-colons are
in place. Amazingly, the missing semi-colon, at the end of the immediately
preceding program statement was not noticed. Please realize that the compiler does
not have intelligence. Certain syntax rules must be obeyed and failure to obey the
syntax rules will cause problems. However, the compiler does not necessarily
recognize what you did wrong or where. What happens is that your error brings
about something that is not digestible to the compiler. At the moment that it is clear
that a mistake is made, the compiler will let you know. This can be many lines
below the actual mistake.
To make matters worse, it is possible that the mistake is not realized until some
library is included. You will now get an error message that stops with a highlighted
bar inside a library that you did not create. This is a major source of frustration. It is
possible that some include libraries have mistakenly been altered, and it is also
possible that the libraries are corrupted. However, in the majority of cases the
libraries are just fine and you are suffering from a program statement error that is not
detected until much later in the compile sequence.
To illustrate the point that the compiler is easily fooled about the error location look
at program PROG1503.CPP on the next page. The program will not compile. Can
you tell what is wrong?
// PROG1503.CPP
// This program demonstrates how one type of program
error can
// cause a totally different syntax error message
somewhere else
#include <iostream.H>
#include <conio.h>
void main()
When you attempt to compile this program, you will get an error message that
specifies Unknown identifier on your screen. Does that make any sense? Variable
identifier GCF is defined, is it not? Well yes, you defined GCF, but the compiler
does not realize this. The problem is that Remainder did not finish with a proper
comment. The result is that GCF becomes part of a comment.
In other words the mistake is not finishing the comment properly. Do not bother me
with statements about using the other comment style that does not require a closing
comment symbol. With this type of mistake the compiler stops at a totally different
location, and gives a message quite different from the mistake made. Actually the
compiler's response and its error message is quite logical, but only to people who
have programmed for quite a while. The main point is, that you can often expect
error messages that are poor indicators of actual mistakes, and the location where the
compilers stops is not always too accurate either. You are not pleased right now. At
this stage of your computer science development you get the distinct feeling that the
It really is not all that bad. With some practice the messages do make sense, but you
can code your programs in such a way that you pretty well know what and where the
mistakes must have been made. The secret is in using STUBS when you write your
programs, and following a logical sequence of coding your program. You are no
stranger to using stubs. This excellent program development feature was already
introduced in the earlier Program Modularity chapter. A brief stub review is given
here. Furthermore, the first introduction to stubs did not include the issue of
parameter passing. Stubs and parameters work closely together to help writing
programs that are easy to debug.
Stub Example:
Every step of the proper stub sequence will not be shown. I will only show you two
programs. First, the main function with all the initial stubs. This is the so-called
first stub stage, which does compile. Second, the completed program.
The biggest source of errors, for students at this stage, are errors caused by using
parameters incorrectly. It certainly makes a lot of sense to insure that your program
uses proper parameter passing at the early stages of program development. The very
first stub stage, which should compile, will catch any of the more common errors
made with parameters.
// PROG1504.CPP
// This program computes employee wages.
// The first stub stage is demonstrated.
#include <iostream.h>
#include <conio.h>
void main()
{
double PayRate; // amount paid per hour
int HoursWorked; // number of hours worked per week
double GrossPay; // total amount earned in one week
double NetPay; // weekly take-home pay after
deductions
clrscr();
EnterData(PayRate,HoursWorked);
ProcessData(PayRate,HoursWorked,GrossPay,NetPay);
DisplayData(GrossPay,NetPay);
getch();
}
Notice how nice and compact this program is. You can see the main function. You
can see the prototypes and you can see the function stubs. If this stage does not
compile, you are able to count the actual and formal parameters. You can also easily
check the data types to make sure that they match. Make sure that you do more at
this initial stage. Compiling is only part of the total program package. The program
needs to be logically correct. Check carefully and make sure that you have correctly
The intermediate stages, of completing each one of the stubs in turn, is not shown.
This is identical to the early stub explanation, introduced in chapter 8. The next
page shows the completed program.
// PROG1505.CPP
// This program computes employee wages.
// This is the final stage after every module is completed.
#include <iostream.h>
#include <conio.h>
#include <iomanip.h>
void main()
{
double PayRate; // amount paid per hour
int HoursWorked; // number of hours worked per week
double GrossPay; // total amount earned in one week
double NetPay; // weekly take-home pay after deductions
clrscr();
EnterData(PayRate,HoursWorked);
ProcessData(PayRate,HoursWorked,GrossPay,NetPay);
DisplayData(GrossPay,NetPay);
getch();
}
In the greater majority of cases you will receive some kind of error message. Your
first step with execution errors is to see if the message makes sense. C++ will also
take the cursor to the location where it suspects the error has been made. As was
pointed out with syntax errors, it is quite possible that the computer is fooled. The
execution error may be at some other location then indicated.
Even more uncomfortable are the errors that cause a computer crash and there is no
message at all. Sometimes you may even have to re-boot the system. At other times
the computer is so distraught by the nature of your error that a courtesy reboot is
automatically performed. Whether you get a message or not, your first task is to
isolate the program segment that causes the runtime error.
All the modern C++ compilers have some type of debugging tool. These tools are
often a good help in identifying problems. The use of such tools is not covered here.
However, there is something that can be done with every compiler without the use of
any special debugging help. If you are using the stub method, you should already be
able to identify the offending function. Make sure that you not only compile the
program after completing each function, but also run the program. This approach
will help to pinpoint the function location of both syntax and runtime errors.
Another problem may occur when some of your functions become quite large.
Further isolation of the problem can be done by using CHECK statements. The
statements are placed at intervals in your program and help to locate the error. You
need to use something like the program segment below.
Initially you may have the CHECK statements pretty far apart. After you run the
program you will find a rough “crash” location. At that point you might decide to
place the CHECK statements closer together. Sometimes you need to narrow down
the checking to a single statement.
You might wonder what causes a runtime error? The compiler has checked the
syntax and the syntax is fine. An executable code is created and the program does
execute. So what can be wrong now? There are a variety of problems that can be
handled by the computer. The more common runtime error is division by zero.
Another common problem is taking the square root of a negative number. I hope
you realize that checking syntax is not at all the same as checking something like a
division by zero.
Logic Errors
We arrive now at the toughest error of them all, the logic error. Why are logic
errors toughest? Simply because the computer gives zero help in the logic error
department. This baby is strictly your affair and if you are not careful you will get
bitten severely. But first things first, what is a logic error?
One of the biggest problems with logic errors is that many programmers, especially
beginning students, do not realize that a logic error exists. How do you know that
you have this problem? The answer is proper TEST DATA. Consider a simple
example first. Your program assignment involves computing the payroll for a
number of employees. Every employee works 20 or more hours and earns at least
$7.50 per hour. You run your program and look at the results. Some of the
employees earn negative amounts of money. It does not require a programming
genius to figure out that something is wrong. Ironically, there are students who do
not catch such errors. Avoid surprises by using the following steps:
1. Test the program first with easy to tell test data. For
2. Test the program with a set of test data for which the correct
output is known. If you average a set of peculiar numbers,
check the answer first on a calculator.
3. Test the program with a wide variety of data, for every known
path that is possible in the program.
// PROG1506.CPP
Minimum test data requires testing in the four different paths through the program.
This program can have regular pay and 15% deductions, regular pay and 29%
deductions, overtime pay and 15% deductions and overtime pay and 29%
deductions. Thorough testing requires more test data. It is not sufficient to test the
four possible execution paths in the program. You also need to check the border
cases. It is precisely at the borderline situations that many programs produce logic
errors. Thorough testing of the border cases is vital to prevents OBOBs. This,
recently popular, acronym stands for Of By One Bug. It is not unusual that a
program uses a conditional expression such as (X > Y) when the, close but not the
same, expression (X >= Y) should have been used. Unintentionally leaving out
the equal ( = ) sign can only be detected with test data that checks the border cases.
Whether you try to solve your own logic errors, or you are trying to get help from
somebody else, A hard copy of the program listing is vital. Then you can do a
variable trace. This means that you trace the values of the variables as the program
executes. In other words, you become the computer.
If you methodically trace through the program in the proper sequence you should
end up with the same results as the computer, and catch your logic error. You may
also use the technique shown for execution errors. Display values of variables at
intermediate stages to isolate the location where the logic goes haywire.
Carburetor Logic
Every year I meet students who do some really bizarre things to their programs.
These students are motivated, they are hard working and they have good intentions
about completing their program assignments. They also recognize that some things
are wrong with their programs. It is with logic errors that this unique group of
students start using very interesting logic. All of a sudden previously, correct
program segments are gone, only to be replaced with new strange looking code. I
call this Carburetor Logic. This can be explained by the following conversation
between a customer and a mechanic.
Please do not ever expose your teacher to carburetor logic. Strange things may
happen to your teacher. Eye ticks - long under control - return and Vietnam
flashbacks - assumed cured - suddenly return.
In 1985 Lynn Rosier, of Richardson High School, Texas developed a very fine
gradebook program for teachers. This program became an instant success with
teachers, but almost immediately the requests for enhancements started to come in
such as:
Attendance records that use the same class lists as the grade book
Book records that use the same class lists as the grade book
This is only a partial list and you will not be bored with numerous examples of other
programs that have been improved with later versions. This brief section on
program enhancement does not exist in an effort to explain how to enhance a
The point here is that program enhancement is the most natural thing to follow
regular program development. It is never sufficient to finish a program without
regard to proper structure, readability, comments and other important program
design concepts. Any person who finishes a meaningful program with the idea that
it will not be looked at in the future is kidding himself or herself.
It is bad when you cannot understand somebody else's program. It is far worse when
you are totally confused by your very own program design. And this happens
frequently to inexperienced programmers.
If you have paid attention so far in this chapter you may feel very frustrated. Your
programs are supposed to be efficient, which is fine with you. Prior to this chapter
you thought you understood efficiency, but now there happen to be three types of
efficiency.
It does not take a genius to figure out that nice self-documenting identifiers, clear
internal documentation (comments), and one-task-one-module type of programming
gobbles up memory. Well that is great, you either make a program readable, or you
use up a lot of memory. Calling a function is nice for structure and readability, but it
slows down program execution. You can't win. First accept the following fact
about programming.