Chapter Twelve

Flow Control via Logic; Projectiles

In this chapter we begin using some of the control structures that make programming so interesting and that make your programs so intelligent. We will have you write your own program to simulate projectile motion, a standard problem of elementary physics. In Chapter 15, “Differential Equations with Java and Maple” we solve this same problem including air resistance. We start with a review of the kinematic equations, which may be scanned by those familiar with it, and then go to describe program design and control structures.

12.1 PROBLEM: FRICTIONLESS PROJECTILE MOTION

Figure 12.1 is the result of a computer simulations showing the trajectory of a projectile fired from a cannon at time t = 0, with initial velocity V0, at an angle θ relative to the horizon. The projectile remains in the air for a total hang time of T and hits the ground a horizontal distance or range x=R away from the origin.

Problem: write a program to simulate the motion of this projectile. Have it:

1.  store the initial values V0, g, and θ as constants;

2.  compute the “hang time” T from the equations of kinematics;

3.  compute the range R and height H from the equations of kinematics;

image

Figure 12.1 Left: The trajectory of a projectile fired with initial velocity V0 in the θ direction. The nonparabolic curve includes air resistance. Right: The x and y components of V0.

4.  compute the position (x, y) of the projectile for 100 times starting at -T/2 and running in uniform steps to 3T/2.

12.2 THEORY: KINEMATICS

If we ignore air resistance, a projectile has only the force of gravity acting on it. This force causes the projectile to fall towards the center of the earth with a constant acceleration g = 9.8m/s2. The resulting solutions to the equations of motion are

image

Here V0x and V0y are the horizontal and vertical components of the initial velocity, and, as we see from Figure 12.1,

image

Likewise, the x and y components of the velocity as functions of time are:

image

Although the equations of motion yield x and y as functions of time, they do not tell us the shape of the trajectory. For these simple equations it is easy to derive that the shape is a parabola. We will, instead, determine the shape by plotting up the solution, a simpler approach as the equations become more realistic.

We determine the hang time T by observing that at the time of firing t= 0, and landing t= T, the projectile has a height y = 0. If we set y = 0 in (12.1), we obtain an equation for the time at which the height is zero:

image

where we ignore the t=0 solution. Once we know T we find the range R as the horizontal distance x(T):

image

The projectile reaches its maximum height H at the midpoint of the trajectory at time t = T/2 = V0y/g:

image

12.3 COMPUTER SCIENCE: DESIGNING STRUCTURED PROGRAMS

Now that you are into the program construction business, it is a good idea to understand not only the grammar of the language you are writing in, but also the general structure that you should be building into your programs. Books have been written on program design, but then again, it is a good idea not to believe everything you read! Yet, as seems to be true in much of life, it is helpful to follow the rules until you know better. Those who have truly mastered a subject may go on and make new rules. We view programming as a written art that blends elements of science, mathematics, and computer science into a set of instructions to permit a computer to accomplish a scientific goal. Good programs should:

•  give the correct answers;

•  be clear and easy to read, with the action of each part easy to analyze;

•  document themselves for the sake of readers and the programmer;

•  be easy to use;

•  be easy to modify and robust enough to keep giving the right answers;

•  be passed on to others to use and develop further.

One way to make your programs clearer is to structure them. You may have already noticed that sometimes we show our coding examples with indentation, skipped lines, and braces placed strategically. This is done to provide visual clues as to the function of the different program parts (the “structures” in structured programming). In spite of the Java compiler ignoring these visual clues, human readers are aided in understanding and modifying the program by having it arranged in a manner that not only looks good, but also makes the different parts of the program manifest to the eye.

The placement of text on the lines and the skipping of lines to make the purpose of the programming clearer is known as structured programming. We recommend it highly. It is a valuable approach when dealing with control structures, and particularly so when dealing with one control structure nested within another. The basic idea is simple: blocks of code performing specified tasks should be indented and physically isolated to set them apart. Even though, in order to conserve printed space, we do not skip as many lines as we would like to, we recommend that you do!

12.3.1 Flowcharts and Pseudocode

In Figure 12.2 we present a flowchart that illustrates a possible program to compute projectile motion. A flowchart is not meant to be a detailed description of a program, but rather a graphical aide to help visualize its logical flow. As such, it is independent of computer language and is useful for developing and understanding the basic structure of a program. We recommend that you draw some type of flow chart or construct some type of pseudocode every time you write a program. Pseudocode is like a text version of a flowchart in that it also leaves out details and instead focuses on the logic:

image

Figure 12.2 A flowchart illustrating a program to compute projectile motion. On the left are the basic components of the program and on the right are details. When writing a program, first map out the basic components, and then design the structure and fill in the details.

1.  Store g, V0, and θ.

2.  Calculate R and T.

3.  Begin repetition loop 100 over times from -T/2 to 3T/2.

a.  Print out “not yet fired” if t <0.

b.  Print out “grounded” if t>T .

c.  Calculate and print x(t) and y(t).

d.  Print out error message if x > R or y > H.

e.  End loop over time.

4.  End program.

One way of viewing program design is in terms of data flow. Your program starts with some input data, decides what to do with it, does it, and then outputs the results. Usually boxes in flowcharts like Figure 12.3 show actions, while elongated or angled boxes show decisions to be made. The direction of logical flow of the program is shown by the arrows, with flow moving down, except when arrows redirect it.

For our projectile problem, we need to calculate the position for 100 different times. The easiest way to do this is to have the same block of code repeated

image

Figure 12.3 Left: Sequential or linear programming. Right: The if-then-else structure, one of several used in nonlinear programming.

100 times, with only the value of the time t changing. Such a structure is called a loop. Like a clock, it will run for a total time

image

Whence, the time increases by Δt for each repetition of the loop:

image

with the program using its intelligence to decide what to compute and print out depending upon the particular value of t.

12.4 FLOW CONTROL VIA LOGIC

One of the most satisfying aspects of programming is getting the computer to do just what you want. Getting it to do what you want is sometimes direct, as when you evaluate functions in a “calculator” mode, and sometimes subtle, as when you try to make the computer act intelligently and “think” logically about what it should do next. Making a program think logically is done by including symbolic logic with Boolean variables. A Boolean variable is a primitive (built-in) Java data type that is either true or false. A Boolean expression is a combination of variables containing logical operators that evaluate to either true or false. When Boolean expressions are used with control structures in your program, you are able to affect the order in which statements are executed, as well as which statements actually get executed.

12.4.1 Relational and Logical Operators

Conditional operators act between two variables or expressions to form a Boolean expression that is either true or false. There are two types of conditional operators, relational operators and logical operators. Relational operators start with variables like double x and double y, and create a logical relationship between them, for example, x>y, that is either true or false. This logical relationship is stored in a Boolean variable that has the value true or false.

Table 12.1 Relational operators of Java.

Operator

Example

Return true if

>

x>y

x is greater than y

>=

x >= y

x is greater than or equal to y

<

x<y

x is less than y

<=

x <= y

x is less than or equal to y

==

x == y

x and y are equal

!=

x! = y

x and y are not equal

Table 12.2 Logical operators of Java.

Operator

Example

Name

Return true if

&&

x && y

Logical and

x and y both true, conditionally evaluates y

||

x || y

Logical or

either x or y true, conditionally evaluates y

!

!x

Not

x is false

&

x&y

And

x and y both true, always evaluates y

|

x|y

Or

either x or y true, always evaluates y

Table 12.1 gives the relational operators, examples of their use, and conditions under which they evaluate to true results. In each case, the result is either true or false. To illustrate, the Boolean variable x>y is true if the numerical value of x is greater than the numerical value of y. These relational operators are never used in assignment statements. Indeed, for this reason, we introduce the double equal sign == as a relational operator; x = y is an assignment statement, while x == y is a Boolean variable.

Logical operators combine Boolean variables to create more complex expressions, for example, (x > 3) & (y > 4). Table 12.2 shows Java’s logical operators, examples of their use, their logical names, and the conditions under which they evaluate to true results.

The basic logic behind logical operators is that if we have a compound statement constructed from two simpler statements, then the truth table, Table 12.3, determines the truth of the compound statement. We see in the truth table that the logical and is represented by both & and &&, and that the logical or is represented by both | and ||. Either form will work for you. The difference is that the single operator form, such as x|y, always evaluates y even if the result is foretold just by evaluating the first variable x. As a case in point, if x is true, then x|y is true regardless of y. The double operator form evaluates y only if the answer is not foretold by evaluating just x:

Table 12.3 Truth table.

True

False

true and true

true and false

true or true

false and false

true or false

false or false

!false

!true

1>4

false

(1 > 4) | (3 > 2)

true

(1 == 4) & (2 < 1)

false

(1! = 3) & (2! > 4)

true

Believe it or not, what makes the use of logical expressions so powerful is that it is legitimate to combine the different logical expressions to describe the basis for any logical decision.

Exercise: If a is your age in years, w your weight in pounds, and h your height in inches, construct Boolean expressions that will be true only when the following statements are true:

1.  you are old enough to obtain a driver’s license but too young to retire, ((a > 16) & (a < 65));

2.  you are not a teenager;

3.  you are either younger than 20 and less than 150 pounds, or you are older than 40 and more than 6 feet;

4.  you are neither old enough to vote, tall enough to hit your head on a five-foot door frame, nor heavy enough to box in the 132–140 pound division.     ♠

12.4.2 Control Structures

The combination of Boolean expressions and control structures permits you to construct programs that make decisions based on the data at hand. Table 12.4 contains a complete list of the control structures in Java. The type of logic that is possible with these Boolean expressions is shown in the flowcharts of Figures 12.3– 12.5. If you look at both the command in the table and the action in the figure together, you should get a good idea of how the command works.

Table 12.4 Logical flow control structures in Java.

image

The left of Figure 12.3 shows linear or sequential programming, in which the statements are executed in the order in which they are encountered, namely, from top to bottom. Control structures introduce the possibility that the execution of the program may “split” into different paths depending on the values of certain variables, or may repeat certain sections a number of times. If the program does “split,” then the programming is no longer sequential.

The if and its complete form if-then-else, are common control structures. They permit your program to make decisions leading to multiple outcomes, with the decision based on changing situations. To name an instance, if it is raining before 10 AM, then I will take my umbrella. This structure are enhanced with the else option: if it is raining before 10 AM, then I will take my umbrella, else I will take my surfboard.

Consider the flow chart in Figure 12.3 illustrating the if-then-else structure, and the example in Table 12.4. First there is a logical expression constructed with the if statement. If the logical expression is true, then action 1 is executed, else action 2 is executed. In the Java version of this structure shown in Table 12.4, action 1 is the block of statements contained within braces that follow the if (…) statement (no braces needed if only one statement). If action 2 is included, it must be preceded with the word else. It too may be a single statement or a group of statements. If action 2 is left off, we end up with an if-then statement. The word then is assumed in Java but used in other languages.

Figure 12.4 illustrates the for loop, probably the most popular control structure. The for loop is used to make your program iterate; that is, repeat a section of code over and over as long as some condition is true. This is useful for things like summing a series or repeating a calculation until the error gets smaller than some fixed amount. In that a counter is used to keep track of the number of iterations, it is also called a counting loop.

image

Figure 12.4 Left: For-loop iteration (test before action). Right: Do-loop iteration (test after action).

In the first line (header) of the for structure:

there are parentheses containing three fields separated by semicolons. The first one, count = 0, gives the starting value for the counter. The second one, count < 100, gives a Boolean expression. The program will continue to iterate all the statements in braces (action in Figure 12.4) following the for construct as long as this Boolean expression is true. The third argument in the parentheses, count = count + 1, tells how to change the counter after each iteration of the loop. The iteration ends when the Boolean expression is false, at which point the program jumps to the first executable statement after the braces containing the action.

In general, the braces { and } are needed to indicate the beginning and end of the lines of code controlled by some control structure. They are permitted on lines all by themselves, or combined with lines of code. The structure of the program is probably clearer if the braces are on lines all by themselves and if they are indented to indicate the range of action of the control structure. However, in order to save space on the printed page and keep our codes compact, we may not follow that suggested form in all of our examples. If only a single line of code is being controlled, then it is legal to leave off the braces and place that line of code on the same line as the control structure. This is compact and easy to read.

These few ways to incorporate logic into programs are sufficient for the problem at hand. Nevertheless, there are other commands that use a somewhat different approach to control the flow of your program, and we shall now discuss some. Consider again Figure 12.3 illustrating the if-then-else structure. We see in Table 12.4 that the else part of this control structure may have an if-then structure following it to form an if-then-else-if structure. What is more, any number of else-if statements may be included to handle special cases; for example, we may add more else-if statements to assign grades of A+, A-, B+, etc.

image

Figure 12.5 A break iteration.

image

Figure 12.4 also illustrates a do loop. A do loop is very similar to a for loop used earlier, except that an action code in braces is executed first, and then the test is made to determine if the loop is to continue. So it follows that there will always be at least one iteration of a do loop.1

It is common to have a loop’s counter index count be an integer, but it is not a requirement. A for or do loop with noninteger counters is similar to a while loop that loops until a general condition becomes false. For example, err > 0.001. Be that as it may, be warned, round-off error makes it unreliable to demand true equality between two floating-point numbers, or between a float and an integer. By way of example, an ill-advised condition might occur in the for loop starting with

image

where x may never be precisely equal to 100, and so this loop may never end!

Table 12.5 Java’s increment and decrement operators.

Shorthand

Equivalent Expression

Note

i++

i=i+1

Evaluate i before increment

i--

i=i-1

Evaluate i before decrement

++i

i=i+1

Evaluate i after increment

--i

i=i-1

Evaluate i after decrement

To make sure that the loop will eventually stop, it is better to use the greater-than and less-than operators. As case in point, we can always satisfy

for (double x = 0.; x <= 100.; x += 1.)

Counting is done so frequently in programming that many programmers prefer to declare the variable used for the loop counter as part of the loop statement itself. For instance, as we did with double x = 0. above, we could have

for (int count = 0; count <= 100; count = count + 1)

Notwithstanding the extra complication of this construction, it has the advantage of declaring locally those variables that are only used locally.

Finally, Table 12.4 and Figure 12.5 show the action of a break statement within a do loop. A break statement permits the programming to disrupt the normal order of execution within the do loop and send the program out of the loop.

12.4.3 Shorthand Notations

In the for loop in Table 12.4, we incremented the loop counter with the statement count = count + 1;. Regardless of this being perfectly clear, experienced programmers often use shortcuts that are elegant but less clear. Java contains the increment operator ++ and the decrement operator — that, respectively, increase or decrease a variable by 1 without the use of an explicit equal sign. As shown in Table 12.5, they are affixed to the front or rear of a variable for slightly different effects. Wherefrom i++ and i-- increment and decrement at the end of the loop, ++i and --i increment and decrement at the beginning of the loop. More specifically, each evaluates to a different value: i++ or i-- return the value of i before the increment or decrement, while ++i or --i return the value of i after the increment or decrement. Since these operators act on only a single variable, they are called unary operators. As an instance, try out this pseudocode:

i=5

print i++, ++i

Table 12.6 Java’s compound assignment operators.

Operator

Example

Equivalent to

+=

x += y

x=x+y

-=

x -= y

x=x-y

* =

x *= y

x=x * y

/=

x /= y

x=x/y

%=

x %= y

x=x%y

&=

x &= y

x=x&y

|=

x |=y

x=x|y

ˆ=

x ˆ = y

x = xˆy

i=5

print i--, --i

There are occasions when the increment and decrement operators ++ and — are not flexible enough, like when you want to increase a variable by 2 rather than 1. In these cases the compound assignment operators indicated in Table 12.6 are useful. To cite an instance, x += 1 is equivalent to x = x + 1, which in turn is equivalent to x++. Likewise, x += 2, is equivalent to x = x + 2, and x += y is equivalent to x=x+y. Because these operators act on two variables, they are called binary operators.

The switch structure, illustrated in Listing 12.1 gives you a neat way to execute different blocks of code depending upon the value of an integer or Boolean variable. Even though this also is accomplished with a series of if-then statements, as we said, the switch structure is neater. The program Switch.java is used to program our clock radio so that we will wake up to music with our sunlight for different months of the year.

12.5 IMPLEMENTATION: PROJECTILE.JAVA

1.  Before you create your own projectile simulation program, write down the equations to be solved and compose a flowchart or pseudocode that shows the logic of your program. Hand these in.

2.  As an aide to writing your program, base it on a similar program you already have. That being the case, we suggest that you make of copy of Limits.java and save it as Projectile.java.

3.  Add statements to your program, in the part before the for loop, that compute and print out T, H, and R. Test it.

4.  Modify the for loop in Limits.java so that it loops over 100 evenly spaced times from -T/2 to 3T/2.

5.  Within the for loop, use the if statements to decide if the projectile has not yet been fired, if it is in the air, or if it has already hit the ground.

6.  Have your program print out explicit values for t, x(t), and y(t). Also have it print out “not yet fired” or “grounded” as appropriate.

7.  Have your program make a plot of the particle trajectory, preferably with PtPlot.

Listing 12.1 Switch.java

image

12.6 SOLUTION: PROJECTILE TRAJECTORIES

1.  Run your program for a variety of initial conditions, namely, for your choice of different values for V0 and θ. Try some for which you know the expected answer (like θ = 0 and θ = π/2).

2.  Check that the range R increases as the initial velocity V0 increases in magnitude, and as the elevation θ increases from 0 to π/4.

3.  Check that the range R = 0, but that the hang time T ≠ 0, for θ = 90° (this shooting the cannon straight up in the air is not the most clever thing to do).

4.  Check that the y values never exceed the maximum height H.

12.7 KEY WORDS

“op” is common computer jargon for “operation,” such as in “flops” for “floatingpoint operations.” We use it here to save space as well:

air resistance

Boolean variable

break

conditional op

control structure

counting loop

decrement op

drag

if-then-else

increment op

flow control

flowchart

iteration

linear program

logical operators

operator

pseudocode

relational op

repetition structure

structured program

subroutine libe

switch

unary operator

while loop

12.8 SUPPLEMENTARY EXERCISES

1.  Take the program Limits.java from Chapter 10 that uses a for loop to determine machine precision and make a copy of it.

a.  Compile and run Limits.java as a check that it is still running, and to get some output to compare with.

b.  Modify the for loop so that the counter is a double-precision variable. You should get all the same results.

c.  Change the for loop to a while loop that accomplishes the same task. (Hint: while (1.0 + eps ! = 1.0) will repeat the loop until there is no difference between the stored values of 1.0 + eps and 1.0.)

d.  Change the for loop to a do loop that accomplishes the same task.

e.  Include an if-then construct in the for loop so that the program prints only one line of output, and it is for the first time that 1.0 + eps = 1.0.

f.  Include an if-then-else construct in the for loop so that the program prints the message “not there yet” if 1.0 + eps! = 1.0, and then the usual onePlusEps and eps the first time that 1.0 + eps = 1.0.

2.  If a is your age in years, w is your weight in pounds, and h is your height in inches, construct Boolean expressions that will be true only when the following conditions are met:

a.  you are old enough to obtain a driver’s license and you do not weigh 1,000 pounds;

b.  you are not a teenager;

c.  you are either younger than 20 and less than 150 pounds, or older than 40 and taller than 6 feet;

d.  you are neither old enough to vote, tall enough to hit your head on a five-foot door frame, nor heavy enough to box in the 132–140-pound division.

3.  Let A be your age, Y be the number of years you have been in college, and D be the number of dollars you have in the bank. Construct Boolean expressions that will be true when the following conditions are met:

a.  you are a millionaire but you are not a senior;

b.  you are either too young to vote or you are not a freshman;

c.  you are either younger than 20 and broke, or older than 90 and have more than $100,000;

d.  you are 16 years old and your number of years in college is greater than the number of dollars you have in the bank.

Listing 12.2 Iterate.java

image

4.  Iteration refers to the repetition of the same lines of code until a condition is satisfied. To illustrate, in Listing 12.2 is a code that computes 1/1 - x for x2 <1 via its infinite series expansion:

image

  The summation of terms is repeated 1,000 times or until the new terms have an insignificant effect on the sum (xn < 10-7 sum).

a.  Enter, compile, and execute Iterate.java. Check that it runs with no errors.

b.  Try several positive values of x< 1. Check that convergence is obtained in each case, but with a differing number of terms needed.

c.  See how close you are able to get to x 1 before the algorithm fails, namely, 1,000 summations are made.

d.  The series (12.12) is valid for negative x values, but the code has assumed that x> 0. Modify the program so that it will work for negative x, and check your results for x = —0.5, —0.1, and —0.9.

1Hoping not to confuse the reader, we note that the Do loop in Fortran executes the action after the test, and is thus equivalent to Java’s for loop, not the do loop.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset