Chapter 3: Decision Structures and Boolean Logic

Modern elevators are strange and complex entities. The ancient electric winch and "maximum-capacity-eight-persons" jobs bear as much relation to a Sirius Cybernetics Corporation Happy Vertical People Transporter as a packet of mixed nuts does to the entire west wing of the Sirian State Mental Hospital. This is because they operate on the curious principle of "defocused temporal perception." In other words they have the capacity to see dimly into the immediate future, which enables the elevator to be on the right floor to pick you up even before you knew you wanted it, thus eliminating all the tedious chatting, relaxing and making friends that people were previously forced to do while waiting for elevators. Not unnaturally, many elevators imbued with intelligence and precognition became terribly frustrated with the mindless business of going up and down, up and down, experimented briefly with the notion of going sideways, as a sort of existential protest, demanded participation in the decision-making process and finally took to squatting in basements sulking."

-Douglas Adams, The Hitchhiker's Trilogy

In addition to calculations, programs also have the ability to decide whether or not to execute a part of an algorithm. Specific action(s) that are only performed if a condition is met are referred to as decision structures. Python provides us with an if and an else statement for decision making.

Definition: Decision Structure

A specific action that is only performed if a condition exists.

Many times when one programs a decision structure, they have to make a comparison between values to make a decision. Comparison operators are used to make this type of decision.

Definition: Comparison Operators

Compares two values and determines if a statement should execute or not.

A decision structure that makes a comparison and only provides on path of execution is referred to as a single-alternative decision structure. As an example, an if statement that only executes if a condition is met, is a single alternative decision structure.

Definition: Single Alternative Decision Structure

A single-alternative decision structure provides only one alternative path of execution.

Example: Single Alternative Decision Structure
In [1]:
#Single Alternative Decision Structure 

theAnswer = int(input("What is the answer to the ultimate question: "))

if theAnswer == 42:
    print("Correct!")
What is the answer to the ultimate question: 42
Correct!

  • In the above example, we tested for equality using the == operator. == only returns True if the user inputs 42.

  • Say we wanted to create another path of execution to let the user know that their answer to the ultimate question was incorrect. The way we would do this is by using the else operator. This decision structure is referred to as a dual-alternative decision structure.

    Definition: Dual Alternative Decision Structure

    A dual-alternative decision structure provides two possible paths of execution.

    Example: Dual Alternative Decision Structure
    In [2]:
    #Dual Alternative Decision Structure 
    
    theAnswer = int(input("What is the answer to the ultimate question: "))
    
    if theAnswer == 42:
        print("Correct!")
    else:
        print("Incorrect!")
    
    What is the answer to the ultimate question: 2
    Incorrect!
    

    What if we need to create a decision structure with multiple alternatives? Python provides us with an additional conditional operator, elif to acheive this functionality.

    In [3]:
    #Multiple Alternative Decision Structure 
    
    theAnswer = int(input("What is the answer to the ultimate question: "))
    
    if theAnswer == 42:
        print("Correct!")
    elif theAnswer > 42:
        print("Too big!")
    else:
        print("Too small!")
    
    What is the answer to the ultimate question: 43
    Too big!
    

    Conditional operators will always return a boolean. In addition to testing for equality, we can also use many other built in relational operators to help our programs make decisions.

    Definition: Relational Operator

    Determines whether a specific relationship exists between two values.

    Example: Relational Operators
    In [4]:
    #Less Than
    
    theAnswer = 42
    
    print(theAnswer < 100)
    
    True
    
    In [5]:
    #Greater Than
    
    theAnswer = 42
    
    print(theAnswer > 100)
    
    False
    

    Here are some more relational operators.

    Operation Name Operator Explanation
    less than < Less than operator.
    greater than > Greater than operator.
    less than or equal <= Less than or equal to operator.
    greater than or equal >= Greater than or equal to operator.
    equal == Equality operator.
    not equal != Not equal operator.

    Sometimes a decision structure will need to test multiple conditions to see if it should execute. Python provides us with three incredibly useful logical operators for this situation, and, or, and not.

    Definition: Logical Operator

    Operators that test boolean values.

    Operation Name Operator Explanation
    logical and and Both operands are True for the result to be True.
    logical or or One or the other operand is True for the result to be True.
    logical not not Negates the truth value, False becomes True, True becomes False.
    In [6]:
    #And
    
    floorOne = 10
    floorTwo = 5
    
    if floorOne > 2 and floorTwo > 2:
        print("The elevator is too lazy to pick you up on that floor, please use the stairs.")
    
    The elevator is too lazy to pick you up on that floor, please use the stairs.
    
    In [7]:
    #Or
    
    floorOne = 1
    floorTwo = 5
    
    if floorOne > 2 or floorTwo > 2:
        print("The elevator is too lazy to pick you up on that floor, please use the stairs.")
    
    The elevator is too lazy to pick you up on that floor, please use the stairs.
    
    In [8]:
    #Not
    
    distanceTooFar = False
    
    if not distanceTooFar:
        print("The elevator will pick you up.")
    
    The elevator will pick you up.
    

    The basis of all logic in a computer is the transistor. Every computer has an insane number of transistors. Transistors are typically made of silicon, which as you may know does not normally allow electricity to flow through it. Silicon is therefore considered a semiconductor. By doping silicon with different materials, you can get it to behave more like a conductor, or more like a resistor. Typically, an N-type semiconductor carries an electric current out, and a P-type semiconductor carries current in.

    A transistor is made up of a base current, that is either on or off, and a stack of PNP type semiconductors. When a current is applied to the base, there is an amplified current, and when there is no current to the base, there is a low current output. An amplified current output corresponds to a 1, and a low current output corresponds to a 0.

    This is the concept behind logic. A 1, or a 0. The hard disk of your computer is made up of millions of molecules that are positively or negatively charged, indicating a 1 or a 0 in memory. Additionally, every instruction on your cpu is at it's core a combination of 1's and 0's. As the read/write head of your computer searches the hard disk, it reads or writes a 1 or a 0. The game of computer science is to figure out the best ways to push around electrons, 1's and 0's to complete tasks and model the real world to solve problems.

    Logic gates like the and, or, and not gate are simply different combinations of transistors.

    In [9]:
    #Or
    
    print(1 or 0)
    print(0 or 1)
    print(1 or 1)
    print(0 or 0)
    
    1
    1
    1
    0
    
    In [10]:
    #And
    
    print(1 and 0)
    print(0 and 1)
    print(1 and 1)
    print(0 and 0)
    
    0
    0
    1
    0
    
    In [11]:
    #Not
    
    print(not 1)
    print(not 0)
    
    False
    True
    

    Let's combine all of this information about decision structures and boolean logic to expand upon our weighted average problem from chapter 2 and display letter grades as well as weighted average.

    In [13]:
    #Input
    testOne = float(input("Please provide a grade for test 1:"))    
    testTwo = float(input("Please provide a grade for test 2:"))
    testThree = float(input("Please provide a grade for test 3:"))
    
    weightedAverage = 0.0
    
    #Process
    weightedAverage = (testOne * .25)+(testTwo * .25)+(testThree * .50)
    
    if weightedAverage <= 100 and weightedAverage >=90:
        grade = "A"
    elif weightedAverage < 90 and weightedAverage >=80:
        grade = "B"
    elif weightedAverage < 80 and weightedAverage >=70:
        grade = "C"
    elif weightedAverage < 70 and weightedAverage >=60:
        grade = "D"
    else:
        grade = "F"
    
    #Output
    print("Weighted Average\tLetter Grade")
    print(weightedAverage,"\t\t\t",grade)
    
    Please provide a grade for test 1:70
    Please provide a grade for test 2:80
    Please provide a grade for test 3:90
    Weighted Average	Letter Grade
    82.5 			 B