In all the loops used so far, the exact number of loop repetitions required
could be determined before the start of loop execution. We used the
FOR
statement to implement these counting loops.
Ada's FOR
loop is limited in that counting can proceed only
over a range that is discrete (i.e., of an integer or enumeration type).
Furthermore, the counter variable is updated by taking its successor (or
predecessor if REVERSE
is used)-- either adding 1 (subtracting 1)
if it is an integer counter or taking the Succ
(Pred
)
attribute if it is an enumeration counter. This means that counting cannot
proceed, for example, by 2s. In many programming situations, the exact number
of loop repetitions cannot be determined before loop execution begins. It may
depend on some aspect of the data that is not known beforehand but usually can
be stated by a condition. For example, we may wish to continue writing checks
as long as our bank balance is positive, as indicated by the following
pseudocode description.
WHILE the balance is still positive LOOP Read in the next transaction Update and print the balance END LOOP;
The actual number of loop repetitions performed depends on the type of each transaction (deposit or withdrawal) and its amount.
To summarize, there are three kinds of looping problems where the Ada
FOR
statement cannot be used:
Float)
;
The first two cases are called counter-controlled loops; they are
still controlled by counters even though a FOR
statement cannot be
used. The third case is often called an event-controlled loop, because
some arriving event, in the input data or some user interaction, triggers the
end of the loop. In cases like these there are other alternatives for writing
conditional loops in Ada. Ada provides two additional looping statements
(WHILE
and general LOOP
) to implement conditional
loops. The WHILE
statement is discussed next; the general
LOOP
statement is introduced later in the chapter.
Example 6.1
Program
6.1 displays the odd numbers from 1 to 39, inclusive. Because the step size
is not 1, we cannot use a FOR
loop for this. A WHILE
structure is used instead. A variable OddNumber
is declared and
used to control the loop. OddNumber
is initialized to 1 before the
WHILE
statement is reached; the WHILE
loop heading
WHILE OddNumber <= 39 LOOPcontrols the condition for continuing the loop. Inside the loop body,
OddNumber
is incremented:
OddNumber := OddNumber + 2;
The loop body is repeated as long as the WHILE
condition remains true. This is tested at the top of each iteration. If the
condition is false, the loop is ended and control passes to the statement
following END LOOP
.
Program 6.1
WITH Ada.Text_IO; WITH Ada.Integer_Text_IO; PROCEDURE Odd_Numbers IS ------------------------------------------------------------------------ --| Displays odd numbers from 1 to 39, inclusive --| Author: Michael B. Feldman, The George Washington University --| Last Modified: July 1995 ------------------------------------------------------------------------ OddNumber : Integer; BEGIN -- Odd_Numbers OddNumber := 1; WHILE OddNumber <= 39 LOOP Ada.Integer_Text_IO.Put(Item => OddNumber, Width => 3); OddNumber := OddNumber + 2; END LOOP; Ada.Text_IO.New_Line; END Odd_Numbers;Sample Run
1 3 5 7 9 11 13 15 17 19 21 23 25 27 29 31 33 35 37 39Example 6.2:
Program 6.2 displays a table of Celsius and equivalent Fahrenheit temperatures for the range of temperatures from 100 degrees Celsius to -20 degrees Celsius in steps of -10 degrees. The assignment statement
Fahrenheit := (1.8 * Celsius) + 32.0;converts each Celsius value in this range to a real Fahrenheit value. You can check this formula by knowing the freezing points (0 and 32 degrees) and boiling points (100 and 212 degrees) in the two systems. Because an integer can't be multiplied by 1.8 and the step size is not 1, a
WHILE
statement is used instead of a FOR
.
Three Float
constants are declared in the program.
CStart
is the starting value of the Float
loop
control variable Celsius
, CLimit
is the limit value,
and CStep
is the step value. The loop is executed for values of
Celsius
in the sequence 20.0, 15.0, 10.0, ... , -15.0, -20.0.
Program 6.2
WITH Ada.Text_IO; WITH Ada.Float_Text_IO; PROCEDURE Temp_Table IS ------------------------------------------------------------------------ --| Displays a table of Fahrenheit and --| equivalent Celsius temperatures. --| Author: Michael B. Feldman, The George Washington University --| Last Modified: July 1995 ------------------------------------------------------------------------ CStart : CONSTANT Float := 100.0; -- initial Celsius temp CStep : CONSTANT Float := -10.0; -- change in Celsius temp CLimit : CONSTANT Float := -20.0; -- final Celsius temp Celsius : Float; -- Celsius temp Fahrenheit : Float; -- Fahrenheit temp BEGIN -- Temp_Table Ada.Text_IO.Put(Item => "Celsius Fahrenheit"); Ada.Text_IO.New_Line (Spacing => 2); Celsius := CStart; WHILE Celsius >= CLimit LOOP Fahrenheit := 1.8 * Celsius + 32.0; Ada.Float_Text_IO.Put (Item => Celsius, Fore => 4, Aft => 0, Exp => 0); Ada.Text_IO.Put(Item => " "); Ada.Float_Text_IO.Put (Item => Fahrenheit, Fore => 3, Aft => 1, Exp => 0); Ada.Text_IO.New_Line; Celsius := Celsius + CStep; END LOOP; END Temp_Table;Sample Run
Celsius Fahrenheit 100.0 212.0 90.0 194.0 80.0 176.0 70.0 158.0 60.0 140.0 50.0 122.0 40.0 104.0 30.0 86.0 20.0 68.0 10.0 50.0 0.0 32.0 -10.0 14.0 -20.0 -4.0Example 6.3
Program
6.3 traces the progress of a hungry worm approaching an apple. Each time it
moves, the worm cuts the distance between itself and the apple by its own body
length until the worm is close enough to enter the apple. A WHILE
loop is the correct looping structure to use because we have no idea beforehand
how many moves are required.
Program 6.3
WITH Ada.Text_IO; WITH Ada.Float_Text_IO; PROCEDURE Worm_and_Apple IS ------------------------------------------------------------------------ --| Displays distances between a worm and an apple. --| The worm keeps reducing the distance by its body length --| until it is close enough to bite the apple. --| Author: Michael B. Feldman, The George Washington University --| Last Modified: July 1995 ------------------------------------------------------------------------ SUBTYPE NonNegFloat IS Float RANGE 0.0 .. Float'Last; WormLength: CONSTANT NonNegFloat := 3.5; -- worm length in inches InitialDist: NonNegFloat; -- input - starting distance from apple Distance: NonNegFloat; -- output - distance between worm and apple BEGIN -- Worm_and_Apple Ada.Text_IO.Put (Item => "Initial distance (float) between worm and apple > "); Ada.Float_Text_IO.Get(Item => InitialDist); Ada.Text_IO.New_Line; -- Cut the distance between the worm and the apple by the worm's -- body length until the worm is close enough to bite the apple Distance := InitialDist; WHILE Distance > WormLength LOOP Ada.Text_IO.Put(Item => "The distance is "); Ada.Float_Text_IO.Put(Item => Distance, Fore=>4, Aft=>2, Exp=>0); Ada.Text_IO.New_Line; Distance := Distance - WormLength; -- reduce Distance END LOOP; -- Display final distance before entering the apple. Ada.Text_IO.New_Line; Ada.Text_IO.Put(Item => "Final distance between worm and apple is "); Ada.Float_Text_IO.Put(Item => Distance, Fore=>4, Aft=>2, Exp=>0); Ada.Text_IO.New_Line; Ada.Text_IO.Put(Item => "The worm bites the apple."); Ada.Text_IO.New_Line; END Worm_and_Apple;Sample Run
Initial distance (float) between worm and apple > 12 The distance is 12.00 The distance is 8.50 The distance is 5.00 Final distance between worm and apple is 1.50
The
assignment statement just before the loop initializes the variable
Distance
to the starting distance (12.0), which was previously
read into InitialDist
. Next, the loop header is reached and the
loop repetition condition (or WHILE
condition)
Distance > WormLength
is evaluated. Because this condition is true, the loop body
(through END LOOP
) is executed. The loop body displays the value
of Distance
, and the statement
Distance := Distance - WormLength; --reduce Distancereduces the value of
Distance
, thereby bringing
the worm closer to the apple. The loop repetition condition is tested again
with the new value of Distance
(8.5); because 8.5 > 3.5 is
true, the loop body displays Distance
again, and
Distance
becomes 5.0. The loop repetition condition is tested a
third time; because 5.0 > 3.5 is true, the loop body displays
Distance
again, and Distance
becomes 1.5. The
loop
repetition condition is tested again; because 1.5 > 3.5 is false, loop
exit
occurs, and the statements following the loop end are executed.
It is important to realize that the loop is not exited at the exact
instant
that Distance
becomes 1.5. If more statements appeared in the
loop body after the assignment to Distance
, they would be
executed. Loop exit does not occur until the loop repetition condition is
retested at the top of the loop and found to be false.
Just as in the counting loops in Chapter 5, there
are three critical steps in
Program
6.3 that involve the loop control variable Distance
:
Distance
is initialized to InitialDist
before the loop header is reached.
Distance
is tested before each execution of the loop
body.
Distance
is updated (reduced by 3.5) during each
iteration. Every WHILE
loop must contain initialization,
test, and update steps. Unlike a FOR
, which has a
very strict syntax, in a WHILE
the initialization and update steps
can be arbitrary statements. Therefore, the compiler cannot check to ensure
that you have included them, so you must be careful. If the first step is
missing, the initial value of Distance
will be meaningless. The
last step ensures that we make progress toward the final goal (Distance
<= WormLength
) during each repetition of the loop. If the last step
is missing, the value of Distance
cannot change, so the loop will
execute "forever" (an infinite loop). The WHILE
loop is described
in the next display.
SYNTAX DISPLAY
WHILE Statement
WHILE expression LOOP statement sequence END LOOP;
PowerOf2 := 1; WHILE PowerOf2 < 10000 LOOP MyInt_IO.Put (Item => PowerOf2); PowerOf2 := PowerOf2 * 2; END LOOP;
WHILE
) the expression is true. When the
expression is tested and found to be false, the WHILE
loop is
exited and the next program statement after END LOOP
is executed.
Note: If the expression evaluates to false the first time it is tested, the
statement sequence will not be executed.Example 6.4
It is instructive to compare the two loop forms that we currently
know how to write: the FOR
loop and the WHILE
loop.
We can always implement a FOR
loop using a WHILE
loop, but we cannot always implement a WHILE
loop using a
FOR
loop. The WHILE
loop shown below behaves
identically to the FOR
loop shown above it.
FOR i IN 1..5 LOOP Square := i * i; Ada.Integer_Text_IO.Put (Item => i, Width => 1); Ada.Integer_Text_IO.Put (Item => Square, Width => 1); Ada.Text_IO.New_Line; END LOOP; i := 1; WHILE i <= 5 LOOP Square := i * i; Ada.Integer_Text_IO.Put (Item => i, Width => 1); Ada.Integer_Text_IO.Put (Item => Square, Width => 1); Ada.Text_IO.New_Line; i := i + 1; END LOOP;
We can make the following observations about the two loop forms just shown:
1. The statement i := 1;
before the WHILE
loop
initializes i
to 1
. The initialization of the
FOR
loop control variable i
is specified in the
FOR
loop header statement.
2. The statement i := i+1;
in the WHILE
loop body
increments i by 1. This step is implicit in the FOR
loop.
3. Unlike the FOR
statement, in which the counter variable is
declared implicitly and has no existence outside the loop body, the loop
variable in the WHILE
is a "normal" variable: It must be declared,
and it is known outside the loop body just like any other variable.
Wherever possible, use a FOR
loop, rather than a
WHILE
loop, to implement a counting loop.
Example 6.5
The distance traveled in t seconds by an object dropped from a
tower is represented by the formula distance = 1/2 × gt2,
where g is the gravitational constant.
Program
6.4 displays a table showing the height of a falling object at fixed time
intervals after it is dropped from a tower and before it hits the ground. The
number of lines in the table depends on the time interval between lines
(DeltaT
) and the tower height (Tower
), both of which
are data values. During each iteration, the current elapsed time
(t
) and the current object height (Height
) are
displayed. Next, the elapsed time is incremented by DeltaT
and the
new object height is computed. The message following the table is displayed
when the object hits the ground. The sample output shows the result of dropping
an object from a tower approximately the height of the Washington Monument (150
meters).
Program 6.4
WITH Ada.Text_IO; WITH Ada.Float_Text_IO; PROCEDURE Free_Fall IS ------------------------------------------------------------------------ --| Displays the height of an object dropped --| from a tower until it its the ground. --| Author: Michael B. Feldman, The George Washington University --| Last Modified: July 1995 ------------------------------------------------------------------------ SUBTYPE NonNegFloat IS Float RANGE 0.0 .. Float'Last; g : CONSTANT NonNegFloat := 9.80665; -- gravitational constant Height: Float; -- input - height of object Tower: NonNegFloat; -- input - height of tower DeltaT: NonNegFloat; -- input - time interval t: NonNegFloat; -- output - elapsed time BEGIN -- Free_Fall -- Enter tower height and time interval. Ada.Text_IO.Put (Item => "Please enter all values in floating-point form."); Ada.Text_IO.New_Line; Ada.Text_IO.Put(Item => "Tower height in meters > "); Ada.Float_Text_IO.Get(Item => Tower); Ada.Text_IO.Put(Item => "Time in seconds between table lines > "); Ada.Float_Text_IO.Get(Item => DeltaT); Ada.Text_IO.New_Line(Spacing => 2); -- Display object height until it hits the ground. Ada.Text_IO.Put(Item => " Time Height"); Ada.Text_IO.New_Line; t := 0.0; Height := Tower; WHILE Height > 0.0 LOOP Ada.Float_Text_IO.Put(Item => t, Fore => 8, Aft => 3, Exp => 0); Ada.Float_Text_IO.Put(Item => Height, Fore=>8, Aft=>3, Exp=>0); Ada.Text_IO.New_Line; t := t + DeltaT; Height := Tower - 0.5 * g * (t ** 2); END LOOP; -- Object hits the ground. Ada.Text_IO.New_Line; Ada.Text_IO.Put(Item => "SPLATT!!!"); Ada.Text_IO.New_Line; END Free_Fall;Sample Run
Please enter all values in floating-point form. Tower height in meters > 150 Time in seconds between table lines > 0.5 Time Height 0.000 150.000 0.500 148.774 1.000 145.097 1.500 138.968 2.000 130.387 2.500 119.354 3.000 105.870 3.500 89.934 4.000 71.547 4.500 50.708 5.000 27.417 5.500 1.674 SPLATT!!!
WHILE
loop may be executed?
CountMoves
) made by the worm before biting
the apple? Which is the loop control variable, Distance
or
CountMoves
?
X := 3; Count := 0; WHILE Count < 3 LOOP X := X * X; Ada.Integer_Text_IO.Put(Item => X); Count := Count + 1; END LOOP;
Count := Count + 2;
CountYears
) it
takes for the population to go over 30,000.
Copyright © 1996 by Addison-Wesley Publishing Company, Inc.