Often what appears to be a new problem will turn out to be a variation of one that you have already solved. Consequently, an important skill in problem solving is the ability to recognize that a problem is similar to one solved earlier. As you progress through your education, you will start to build up a collection of programs and procedures. Whenever possible, you should try to adapt or reuse parts of a program that have been shown to work correctly.
An experienced programmer usually writes programs that can be easily changed or modified to fit other situations. One reason for this is that programmers (and program users) often wish to make slight improvements to a program after having used it. If the original program is designed carefully from the beginning, the programmer will be able to accommodate changing specifications with a minimum of effort. In the next problem, it is possible to insert a new decision step rather than having to rewrite the entire program.
Case Study: Computing Overtime Pay
Develop a payroll program so that employees who work more than 40 hours a week are paid double for all overtime hours.
This problem is an extension of the modified payroll problem solved by Program 4.1. Employees who work more than 40 hours should be paid one rate for the first 40 hours and a higher rate for the extra hours over 40. Employees who work 40 hours or less should be paid the same rate for all hours worked. We can solve this problem by replacing step 3 (compute gross pay) in the original algorithm with a decision step that selects either a straight pay computation or a computation with overtime pay.
Problem Constants
maximum salary for no tax deduction (TaxBracket = 100.00
)
amount of tax deducted (Tax = 25.00
)
maximum hours without overtime pay (MaxHours = 40.0
)
Problem Inputs
hours worked (Hours : NonNegFloat
)
hourly rate (Rate : NonNegFloat
)
Problem Outputs
gross pay (Gross : NonNegFloat
)
net pay (Net : NonNegFloat
)
The critical change to the algorithm involves modifying step 3 of thealgorithm. The algorithm is repeated below followed by a new refinement for step 3.
1. Display user instructions.
2. Enter hours worked and hourly rate.
3. Compute gross salary including any overtime pay.
4. Compute net salary.
5. Display gross salary and net salary.
Step 3 Refinement
3.1. IF
no overtime hours were worked THEN
3.2. Gross
gets Hours * Rate
ELSE
3.3. Compute Gross
as (the pay for 40 hours) +
(the pay for overtime hours)
END IF;
As shown below, we should replace the assignment statement in Program 4.1 thatcomputes gross pay by
-- Compute gross pay including any overtime pay IF Hours <= MaxHours THEN Gross := Hours * Rate; ELSE Gross := (MaxHours * Rate) + ((Hours - MaxHours) * (2.0 * Rate)); END IF;
If the condition Hours <= MaxHours
is true,
there is no overtime pay, so gross pay is computed as before; otherwise,
Gross
is computed using the second assignment statement above.
The pay for the first 40 hours is added to the pay earned for the overtime
hours (Hours - MaxHours
).
The assignment statement for step 3.3 involves three arithmetic operators:
+
, -
, and *
. As recommended in Section
2.10, we have used parentheses to cause the operators above to be evaluated in
the order of subtraction first, multiplication next, and addition last.
Consequently, the overtime hours (Hours - MaxHours
) are multiplied
by 2.0 * Rate
and added to the value of MaxHours *
Rate
computed earlier; the result is the new value of
Gross
. Modifying
Program
4.1 as discussed here is left as an exercise.
Sometimes a new problem is simply an old one presented in a new guise. Each time you face a problem, try to determine whether you have solved a similar problem before; if you have, adapt the earlier solution. This problem-solving strategy requires a careful reading of the problem statement to detect requirements that may be similar to those of earlier problems but worded differently.
Case Study: Computing Insurance Dividends
Each year an insurance company sends out dividend checks to its policyholders. The dividend amount is a fixed percentage (4.5%) of the insurance premium paid in. If there were no damage claims made by the policyholder, the dividend rate for that policy is increased by 0.5%. Write a program to compute dividends.
This problem is similar to the overtime pay problem. Just as there was a bonuspay rate for workers with overtime hours, there is a bonus dividend for policyholders with no claims. We must first read in the input data (number of claims and premium). We then use a decision step to select either the basic dividend computation or the computation with a bonus dividend. (In the overtime pay problem, we followed a similar algorithm by first computing gross pay, then adding in overtime pay when earned.)
Problem Constants
the fixed dividend rate of 4.5% (FixedRate = 0.045
)
the bonus dividend rate of 0.5% (BonusRate = 0.005
)
Problem Inputs
premium amount (Premium : NonNegFloat
)
number of claims (NumClaims : Natural
)
Problem Outputs
dividend amount (Dividend : NonNegFloat
)
Figure 4.5 shows the structure chart for this algorithm.
Figure
4.5
Structure Chart for Insurance Dividend Problem
Algorithm
1. Display user instructions.
2. Enter premium amount and number of claims.
3. Compute basic dividend including a bonus dividend when earned.
4. Display total dividend.
The refinement of step 3 in this problem is similar to the refinement of step 3 in the overtime pay problem.
Step 3 Refinement
3.1. IF
the basic dividend applies THEN
3.2. Dividend
gets Premium * BasicRate
ELSE
3.3. Dividend
gets basic dividend plus bonus dividend
END IF;
We leave the test plan as an exercise.
The complete program is shown in
Program
4.3. Because Ada possesses no % operator, decimal fractions are required.
The basic dividend rate, 4.5%, is written as the decimal fraction 0.045, and
the bonus rate, 0.5%, is written as the decimal fraction 0.005. All-floating
point literals must begin with a digit; therefore, the zero in front of the
decimal point is always required for a floating-point value less than 1.0. The
IF
statement at the end of the program displays an extra message
to policyholders who receive a bonus dividend.
Program 4.3
WITH Ada.Text_IO; WITH Ada.Integer_Text_IO; WITH Ada.Float_Text_IO; PROCEDURE Dividend IS ------------------------------------------------------------------------ --| Finds and displays the insurance dividend. --| Author: Michael B. Feldman, The George Washington University --| Last Modified: July 1995 ------------------------------------------------------------------------ SUBTYPE NonNegFloat IS Float RANGE 0.0 .. Float'Last; BasicRate : CONSTANT NonNegFloat := 0.045; -- basic dividend rate 4.5% BonusRate : CONSTANT NonNegFloat := 0.005; -- bonus dividend rate 0.5% Premium : NonNegFloat; -- input - premium amount NumClaims : Natural; -- input - number of claims Dividend : NonNegFloat; -- output - dividend amount BEGIN -- Dividend -- Enter Premium and NumClaims Ada.Text_IO.Put (Item => "Premium amount > $"); Ada.Float_Text_IO.Get (Item => Premium); Ada.Text_IO.Put (Item => "Number of claims > "); Ada.Integer_Text_IO.Get (Item => NumClaims); Ada.Text_IO.New_Line; -- Compute divided using bonus rate when earned IF NumClaims /= 0 THEN Dividend := Premium * BasicRate; ELSE Dividend := (Premium * BasicRate) + (Premium * BonusRate); END IF; -- Display total dividend Ada.Text_IO.Put (Item => "Total dividend is $"); Ada.Float_Text_IO.Put (Item => Dividend, Fore => 1, Aft => 2, Exp => 0); Ada.Text_IO.New_Line; IF NumClaims = 0 THEN Ada.Text_IO.Put (Item => "This includes a bonus dividend for zero claims!"); Ada.Text_IO.New_Line; END IF; END Dividend;Sample Run
Premium amount > $1200.00 Number of claims > 0 Total dividend is $60.00 This includes a bonus dividend for zero claims!
Case Study: Given Today, Find Yesterday and Tomorrow
Read the day of the week from the terminal as a three-letter abbreviation, and display yesterday and tomorrow.
Recall from Section
3.4 that the days of the week are best represented as an enumeration type,
so the days can be read and displayed by an instance of
Enumeration_IO
. Yesterday and tomorrow can be found using the
successor and predecessor attributes. Because the predecessor of the first day
of the week and the successor of the last day of the week are undefined--the
type does not "wrap around"--we shall need statements to check for these as
special cases.
Problem Data Types
Days of the week, an enumeration type:
TYPE Days IS (Mon, Tue, Wed, Thu, Fri, Sat, Sun);
Problem Inputs
Today (Today : Days
)
Problem Outputs
Yesterday (Yesterday: Days
)
Tomorrow (Tomorrow: Days
)
1. Prompt the user for the current day abbreviation and read it from the keyboard.
2. Find the abbreviations for yesterday and tomorrow.
3. Display the results on the screen.
Step 2 Refinement
The refinement of step 2 takes into account that in Ada the enumeration types are not cyclic.
2.1. If today is the first day of the week, then yesterday is the last day of the (previous) week; otherwise yesterday is the predecessor of today.
2.2. If today is the last day of the week, then tomorrow is the first day of the (following) week; otherwise tomorrow is the successor of today.
In addition to a normal case, we need to test two special cases, namely, where today is Sunday (to be sure that tomorrow is Monday) and today is Monday (to be sure that yesterday was Sunday). Also test for invalid input that is not one of the seven day abbreviations.
Program 4.4 gives the complete solution to the problem.
Program 4.4
WITH Ada.Text_IO; PROCEDURE Three_Days IS ------------------------------------------------------------------------ --| Finds yesterday and tomorrow, given today --| Author: Michael B. Feldman, The George Washington University --| Last Modified: July 1995 ------------------------------------------------------------------------ TYPE Days IS (Mon, Tue, Wed, Thu, Fri, Sat, Sun); PACKAGE Day_IO IS NEW Ada.Text_IO.Enumeration_IO (Enum => Days); Yesterday : Days; Today : Days; Tomorrow : Days; BEGIN -- Three_Days -- prompt user to enter a day abbreviation Ada.Text_IO.Put (Item => "Enter the first 3 letters of a day of the week > "); Day_IO.Get (Item => Today); -- find yesterday IF Today = Days'First THEN Yesterday := Days'Last; ELSE Yesterday := Days'Pred(Today); END IF; Ada.Text_IO.Put (Item => "Yesterday was "); Day_IO.Put (Item => Yesterday); Ada.Text_IO.New_Line; Ada.Text_IO.Put (Item => "Today is "); Day_IO.Put (Item => Today); Ada.Text_IO.New_Line; -- find tomorrow IF Today = Days'Last THEN Tomorrow := Days'First; ELSE Tomorrow := Days'Succ(Today); END IF; Ada.Text_IO.Put (Item => "Tomorrow is "); Day_IO.Put (Item => Tomorrow); Ada.Text_IO.New_Line; END Three_Days;Sample Run
Enter the first 3 letters of a day of the week > sat Yesterday was FRI Today is SAT Tomorrow is SUN
TESTING
The sample run shows only a normal-case test. To complete the test plan, run the program for the invalid and special cases as well.
Dividend
as two steps. Compute the basic dividend first and then add a bonus dividend
only if there were no claims.
Copyright © 1996 by Addison-Wesley Publishing Company, Inc.