## Two Way Decisions

Now that we have a way to selectively execute certain statements in a program using decisions, it's time to go back and spruce up the quadratic equation solver from Chapter 3. Here is the program as we left it:

# A program that computes the real roots of a quadratic equation.

# Illustrates use of the math library.

# Note: this program crashes if the equation has no real roots, import math # Makes the math library available.

print "This program finds the real solutions to a quadratic" print a, b, c = input("Please enter the coefficients (a, b, c): ")

discRoot = math.sqrt(b *b-4*a*c) rootl = (-b + discRoot) / (2 * a) root2 = (-b - discRoot) / (2 * a)

print print "The solutions are:", rootl, root2 main()

As noted in the comments, this program crashes when it is given coefficients of a quadratic equation that has no real roots. The problem with this code is that when b2 — 4ac is less than 0, the program attempts to take the square root of a negative number. Since negative numbers do not have real roots, the math library reports an error. Here's an example.

This program finds the real solutions to a quadratic

Please enter the coefficients (a, b, c): 1,2,3 Traceback (innermost last): File "<stdin>", line 1, in ? File "quadratic.py", line 21, in ? main()

File "quadratic.py", line 14, in main discRoot = math.sqrt(b *b-4*a*c) OverflowError: math range error

We can use a decision to check for this situation and make sure that the program can't crash. Here's a first attempt:

# quadratic2.py import math def main():

print "This program finds the real solutions to a quadratic\n"

a, b, c = input("Please enter the coefficients (a, b, c): ")

discRoot = math.sqrt(discrim)

print "\nThe solutions are:", root1, root2

This version first computes the value of the discriminant (b2 — 4ac) and then checks to make sure it is not negative. Only then does the program proceed to take the square root and calculate the solutions. This program will never attempt to call math.sqrt when discrim is negative.

Incidently, you might also notice that I have replaced the bare print statements from the original version of the program with embedded newlines to put whitespace in the output; you hadn't yet learned about n the first time we encountered this program.

Unfortunately, this updated version is not really a complete solution. Study the program for a moment. What happens when the equation has no real roots? According to the semantics for a simple if, when b*b - 4*a*c is less than zero, the program will simply skip the calculations and go to the next statement. Since there is no next statement, the program just quits. Here's what happens in an interactive session.

This program finds the real solutions to a quadratic

Please enter the coefficients (a, b, c): 1,2,3 >>>

This is almost worse than the previous version, because it does not give the user any indication of what went wrong; it just leaves them hanging. A better program would print a message telling the user that their particular equation has no real solutions. We could accomplish this by adding another simple decision at the end of the program.

print "The equation has no real roots!"

This will certainly solve our problem, but this solution just doesn't feel right. We have programmed a sequence of two decisions, but the two outcomes are mutually exclusive. If discrim >= 0 is true then discrim < 0 must be false and vice versa. We have two conditions in the program, but there is really only one decision to make. Based on the value of discrim The program should either print that there are no real roots or it should calculate and display the roots. This is an example of a two-way decision. Figure 7.3 illustrates the situation.

In Python, a two-way decision can be implemented by attaching an else clause onto an if. The result is called an if-else statement.

if <condition>:

<statements> else:

<statements>

When the Python interpreter encounters this structure, it will first evaluate the condition. If the condition is true, the statements under the if are executed. If the condition is false, the statements under the else are executed. In either case, control then passes to the statement following the if-else. Using a two-way decision in the quadratic solver yields a more elegant solution.

Figure 7.3: Quadratic solver as a two-way decision.

# quadratic3.py import math def main():

print "This program finds the real solutions to a quadratic\n" a, b, c = input("Please enter the coefficients (a, b, c): ")

print "\nThe equation has no real roots!" else:

discRoot = math.sqrt(b *b-4*a*c) rootl = (-b + discRoot) / (2 * a) root2 = (-b - discRoot) / (2 * a) print print "\nThe solutions are:", rootl, root2 This program fits the bill nicely. Here is a sample session that runs the new program twice. >>> quadratic3.main()

This program finds the real solutions to a quadratic

The equation has no real roots! >>> quadratic3.main()

This program finds the real solutions to a quadratic Please enter the coefficients (a, b, c): 2,4,1 The solutions are: -0.292893218813 -1.70710678119