Skip to main content

Section 4.5 Logical operators—Advanced Topics

This section goes in depth about how logical operators work. If you read this and find it confusing, feel free to skip this page and move on to the next section. After you have worked with logical operators for a while, you might want to return to this section to get “the rest of the story.”
When trying to show how logical operators work, computer scientists and mathematicians will use truth tables. A truth table is a small table that lists all possible inputs on its left columns and then will display the output of its particular logical operator in the right column. Take the logical operator and, for example:
Table 4.5.1.
a b a and b
T T T
T F F
F T F
F F F
The T in the table stands for True while the F stands for False. Notice that when a and b are both True, the logcial operator and outputs True. This is exactly how we normally use “and” in everyday conversation. Here are the rest of the operators:
Table 4.5.2.
a b a and b a or b not a not b
T T T T F F
T F F T F T
F T F T T F
F F F F T T
Let’s check your understanding of these topics:

Checkpoint 4.5.3.

    What is a correct Python expression for checking to see if a number stored in a variable x is between 0 and 5?
  • x > 0 and < 5
  • Each comparison must be between exactly two values. In this case the right-hand expression < 5 lacks a value on its left.
  • x > 0 or x < 5
  • Although this is legal Python syntax, the expression is incorrect. It will evaluate to true for all numbers that are either greater than 0 or less than 5. Because all numbers are either greater than 0 or less than 5, this expression will always be True.
  • x > 0 and x < 5
  • Yes, with an and keyword both expressions must be True so the number must be greater than 0 an less than 5 for this expression to be true. Although most other programming languages do not allow this mathematical syntax, in Python, you could also write 0 < x < 5.

Checkpoint 4.5.4.

    Say you are registering for next semester’s classes. You have choice A, which is your art class, and choice B, which is your math class. You need both of them, but it’s a race between time and luck. If you end up registering on time for choice A, but you don’t get your choice B, which logical operators would be true?
  • A and B
  • Both A and B need to be True in order for this to be True.
  • A or B
  • Either A or B need to be True in order for this to be True.
  • not A
  • A needs to be False in order for this to be True.
  • not B
  • B needs to be False in order for this to be True.

Subsection 4.5.1 Logical Opposites

Each of the six relational operators has a logical opposite: for example, suppose we can get a driving licence when our age is greater or equal to 17, we can not get the driving licence when we are less than 17.
Table 4.5.5.
Operator Definiton Logical Opposites
== Equal to !=
!= Not Equal to ==
< Less than >=
<= Less Than or Equal to >
> Greater Than <=
>= Greater Than or Equal to <
Understanding these logical opposites allows us to sometimes get rid of not operators. not operators are often quite difficult to read in computer code, and our intentions will usually be clearer if we can eliminate them.
For example, if we wrote this Python:
if not (age >= 17):
   print("Hey, you're too young to get a driving licence!")
it would probably be clearer to use the logical opposite of the >= operator instead:
if age < 17:
   print("Hey, you're too young to get a driving licence!")

Subsection 4.5.2 The De Morgan Laws

Two powerful simplification laws (called De Morgan’s laws) that are often helpful when dealing with complicated Boolean expressions are:
not (x and y)  ==  (not x) or (not y)
not (x or y)   ==  (not x) and (not y)
For example, suppose you want to update your phone; however, your phone will only update if it has at least 50% battery life and 15% of its storage available. As we look at the Python code for this, we see:
if not ((phone_charge >= 0.50) and (phone_storage >= .15)):
   print("You cannot restart your phone.")
   print("Battery too low or not enough free space.")
else:
   print("Updating now...Several restarts may be required.")
Applying rules of logical opposites would let us rework the condition in a (perhaps) easier to understand way like this:
if (phone_charge < 0.50) or (phone_storage < .15):
   print("You cannot restart your phone.")
   print("Battery too low or not enough free space.")
else:
   print("Updating now...Several restarts may be required.")
We could also get rid of the not by swapping around the then and else parts of the conditional. So here is a third version, also equivalent:
if (phone_charge >= 0.50) and (phone_storage >= .15):
   print("Updating now...Several restarts may be required.")
else:
   print("You cannot restart your phone.")
   print("Battery too low or not enough free space.")
This version is probably the best of the three, because it very closely matches the initial English statement. Clarity of our code (for other humans), and making it easy to see that the code does what was expected should always be a high priority.
As our programming skills develop we will find we have more than one way to solve any problem. So good programs are designed. We make choices that favour clarity, simplicity, and elegance. The job title software architect says a lot about what we do—we are architects who engineer our products to balance beauty, functionality, simplicity and clarity in our creations.