Spring 2012 CSCI 220 Week 11

= For Loops: A Quick Review = By now you should see the benefit of committing the loop and accumulator pattern to memory. We've used it several times over the semester. An example is a program that computes the average of a set of numbers: def main: n = eval(input("How many numbers do you have?")) sum = 0.0 for i in range(n): x = eval(input("Enter a number >> ")) sum = sum + x   print("\nThe average of the numbers is", sum/n)

main

= Indefinite Loops = This averaging program is certainly functional, but it doesn't have the best user interface. It requires the user to know the number of numbers to average ahead of time. This is OK for a few numbers, but it becomes a burden when we have a large number of values to average. It would be really nice if the program figured out how many numbers we entered while the program was executing.

Unfortunately, the for loop (in its usual form) is a definite loop, which means the number of iterations is determined when the loop starts. The solution to this dilemma lies in another kind of loop: the indefinite or conditional loop.

while :
 * An indefinite loop keeps iterating until certain conditions are met. There is no guarantee ahead of time regarding how many times the loop with execute. In Python, an indefinite loop is implemented using a while statement:

The semantics of a while loop is straightforward. The body of the loop executes repeatedly as long as the condition remains true (See Figure 8.1). Here is an example of a loop that counts from 0 to 10: i = 0 while i <= 10: print(i) i = i + 1

This code will have the same output as if we had written a for loop like this: for i in range(11): print(i)

Notes:
 * We must initialize i before the loop
 * We must increment i in the loop

This flexibility often leads to errors. A common error is an infinite loop: i = 0 while i <= 10: print(i) How many times will the above loop execute?

As a beginning programmer, it would be surprising if you didn't write some programs with infinite loops. I still write programs with the occasional infinite loop. It's a rite of passage! You can usually break out an infinite loop by pressing -c.

= Common Loop Patterns =

Interactive Loops

 * The big idea: repeat certain portions of a program on demand.

We'll use this pattern to create a program for averaging an indefinite number of values. To allow the user to stop entering values, we'll ask whether there is more data to process. Here is some pseudocode:

initialize sum to 0.0 initialize count to 0 set moredata to "yes" while moredata is "yes" input a number, x   add x to sum add 1 to count ask user if there is moredata output sum / count

Note: There are two accumulators that are interleaved into the basic structure of the interactive loop.

Here is the Python program: def main: sum = 0.0 count = 0 moredata = "yes" while moredata[0] == "y": x = eval(input("Enter a number >> ")) sum = sum + x       count = count + 1 moredata = input("Do you have more numbers (yes or no)? ") print("\nThe average of the numbers is", sum / count)

Sentinel Loops
We can improve the previous program using a pattern known as a sentinel loop. A sentinel loop continues to process data until reaching a special value that signals the end, which is called the sentinel. Here is a modified version of our program to use the sentinel pattern: def main: sum = 0.0 count = 0 x = eval(input("Enter a number (negative to quit) >> ")) while x >= 0: sum = sum + x       count = count + 1 x = eval(input("Enter a number (negative to quit) >> ")) print("\nThe average of the numbers is", sum/count)

main

Now we don't have to prompt for values without the hassle of saying "yes" all the time. But we can't enter in negative values. We can change this by accepting strings and numbers as input. We will make the empty string ("") our sentinel:

def main: sum = 0.0 count = 0 xStr = input("Enter a number ( to quit) >> ") while xStr != "": x = eval(xStr) sum = sum + x       count = count + 1 xStr = input("Enter a number (> ") print("\nThe average of the numbers is", sum / count)

main

File Loops
Back in Chapter 5, we wrote a file I/O program: def main: fileName = input("What file are the numbers in? ") infile = open(fileName,'r') sum = 0.0 count = 0 for line in infile: sum = sum + eval(line) count = count + 1 print("\nThe average of the numbers is", sum / count)

main

This works great for those of us who use Python, but may programming languages do not have a special mechanism for looping. This other languages will often use the sentinel loop pattern. We will mimic this in Python by using the readline method: def main: fileName = input("What file are the numbers in? ") infile = open(fileName,'r') sum = 0.0 count = 0 line = infile.readline while line != "": sum = sum + eval(line) count = count + 1 line = infile.readline print("\nThe average of the numbers is", sum / count)

Nested Loops
What if we want to let the user enter in multiple values per line? We can use nested loops to enable this new feature. The best way to design this type of program is to focus on the outer loop first without worrying about the inner loop. Then develop the inner loop without worrying about the outer loop. The more complicated your programs become the more important it becomes to build and test your programs in an incremental fashion. Here is our new program: def main: fileName = input("What file are the numbers in? ") infile = open(fileName,'r') sum = 0.0 count = 0 line = infile.readline while line != "": for xStr in line.split(","): sum = sum + eval(xStr) count = count + 1 line = infile.readline print("\nThe average of the numbers is", sum/count)

= Computing with Booleans =

Boolean Operators
So far we've been focusing on simple conditions. These are often not expressive enough. Suppose you need to determine whether two points are in the same position (i.e., equal x and y coordinates). We could: if p1.getX == p2.getX: if p1.getY == p2.getY: # points are the same else: # points are different else: # points are different This is really awkward, so we will use a more complex Boolean expression. Most programming languages, Python included, implement three Boolean operators: and, or, and not. The Boolean operators and and or are used to combine two Boolean expressions: and or not


 * The and of two expressions is true when both of the expressions are true.
 * The or of two expressions is true when either expression is true.
 * The third operator, not, computes the opposite of a Boolean expression.

As with arithmetic operators, precedence rules must be applied. Consider the following: a or not b and c How should that be evaluated? Turns out it is evaluated: A parenthesized version of the expression above: (a or ((not b) and c))
 * 1) not
 * 2) and
 * or

But most people don't remember this precedence, so I suggest you always parenthesize your complex expressions.

Using these operators we can now test for the co-location of two points: if p1.getX == p2.getX and p2.getY == p1.getY: # points are the same else: # points are different

To demonstrate these operators, let's use racquetball as an example. In racquetball, a game is over as soon as either of the players has reached 15 points: scoreA == 15 or scoreB == 15

while not (scoreA == 15 or scoreB == 15): # continue playing

A more complex expression arises when you consider a mercy rule. A racquetball game can also end when one player reaches 7 if the other person is still at 0. Here is an expression: a == 15 or b == 15 or (a == 7 and b == 0) or (a == 0 or b == 7)

Boolean Algebra
Boolean expressions obey certain algebraic laws, which are called Boolean logic or Boolean algebra. Here are some properties:
 * a or true == true

Both and and or distribute over each other.
 * a or (b and c) == (a or b) and (a or c)
 * a and (b or c) == (a and b) or (a and c)

A double negative cancels out:
 * not(not a) == a

The next two identities are known as DeMorgan's laws.
 * not(a or b) == (not a) and (not b)
 * not(a and b) == (not a) or (not b)

Prove this with a truth table!

This is useful when evaluating an expression. Consider our racquetball example: while not (scoreA == 15 or scoreB == 15): # continue playing

By DeMorgan's law, we can change this to: while (not scoreA == 15) and (not scoreB == 15): # continue playing

Or better yet: while scoreA != 15 and scoreB != 15: # continue playing

= Other common structures =

Post-Test Loop
Suppose you are writing a program that is prompting for a negative number. You don't want your program to continue until they enter a valid number. Here is a simple algorithm (NOT Python code): repeat get a number from the user until number is >= 0

This algorithm loops until a valid number is entered. Python does not have a statement that implements this post-test loop, but you can mimic the behavior with our pre-test loop: number = -1 while number < 0: number = eval(input("Enter a positive number: "))

Some programmers simulate a post-test loop using a break statement: while True: number = eval(input("Enter a positive number: ")) if number >= 0: break # Exit loop if number is valid.

Loop and a Half
Some programmers would solve the warning problem using a slightly different style:

while True: number = eval(input("Enter a positive number: ")) if number >= 0: break # Loop exit print("The number you entered was not positive")

One more thing
Do you think the following code will work? Will it compile? response = "no" while response[0] == 'y' or 'Y': response = input("Type yes/Yes to exit: ")