Skip to main content
Logo image

Section 4.4 Manipulating boolean expressions

Boolean expressions are at the heart of a lot of code controlling what happens when. And sometimes they can get a bit complex. In order to keep from getting overwhelmed, it’s useful to be able to manipulate and simplify boolean expressions.
Also the AP exam almost always includes some questions that depend on your ability to determine whether two boolean expressions are actually equivalent, similar to being able to determine that two mathematical expressions such as \(a(b + c)\) and \(ab + ac\) are equivalent.
In this section we will look at two ways of manipulating and analyzing boolean expressions: algebraically and with truth tables.

Subsection 4.4.1 Compound boolean expressions

As with the arithmetic operators, the two logical operators && and || each apply to only two operands and ! only applies to one. But we can build compound expressions where the operands are other expressions using either other logical operators or comparison operators. We saw some examples of this in the previous section.
Once we start writing compound expressions it’s important to know what the precedence of the different operators are and our middle-school PEMDAS is no help. In Java, ! has higher precedence than &&, and && is higher than ||. But parentheses still have the highest precedence of all so we can use them to group things the way we want them to be evaluated. For example !a && b is equivalent to (!a) && b. If instead we want to negate the value produced by the and expression we can write: !(a && b).
Also all the logical operators are lower precedence than the comparison operators which is why we can write 0 <= x && x < 100 rather than having to write: (0 <= x) && (x < 100).

Subsection 4.4.2 Simplifying algebraically

Once we start writing complex compund boolean expressions things can get out of hand. Sometimes this happens organically as we write code because we add subexpressions to an expression as we realize different cases. β€œI want to run this code when the score is greater than one-hundred. No wait, greater than one-hundred and bonus points are greater than ten. Well, that but also when the player has at least one power up and more than ten bonus points.” Next thing you know we’ve got this (with parentheses added for clarity):
(score > 100 && bonusPoints > 10) || (powerUps > 1 && bonusPoints > 10)
That’s maybe not terrible but it’s not trivial either. When we look at that expression how sure are we that it’s capturing exactly the cases we care about? Luckily there are some techniques for simplifying an expression like that into something that might be easier to understand.
For instance, in this case we can notice that in both sides of the || the condition is something && bonusPoints > 10. Since the whole compound expression can only be true if one side or the other is true but whichever side it is, bonusPoints > 10 will have to be true. So that means we can factor it out similar to how we can factor \(a\) out of \(ab + ac\) to get \(a(b + c)\text{.}\) That gives us this:
bonusPoints > 10 && (score > 100 || powerUps > 1)
This trick also works when we have two || expressions combined with &&. Consider for instance this expression:
(score > 100 || bonusPoints > 10) && (score < 100 || bonusPoints > 10)
This time in order for the whole expression to be true both of the operands to the &&, i.e. the two || expressions have to be true. Since they both contain bonusPoints > 10, if that subexpression is true they will each be true and therefore the whole thing will be true. So we can factor it out like this:
bonusPoints > 10 || (score > 100 && score < 100)
But now there’s an even bigger payoff. Look carefully at the second expression. It’s true when the score is both greater and less than one hundred. Which can never happen so that subexpression will always be false. So we can simplify the larger expression to:
bonusPoints > 10 || false
And since the value of that now depends entirely on the left hand operand of the || we’ve simplified the whole original expression down to just:
bonusPoints > 10

Subsection 4.4.3 De Morgan’s Laws

One of the most powerful tools for manipulating boolean expressions are De Morgan’s Laws. Developed by Augustus De Morgan in the 1800s, they show how to simplify the negation of && and || expressions, i.e. anything in either of these two forms: !(a && b) or !(a || b)
The rule is pretty simple: apply the ! to each of the subexpressions and then switch the other operator with && changing to || and || changing to &&.
Figure 4.4.1. De Morgan’s Laws to simplify complex expressions
In Java, De Morgan’s Laws are written with the following operators:
You can probably convince yourself that these are valid with an actual example. Imagine, for instance, that you are trying to express whether you want to go to the movies. You won’t go if you’re broke or if you’re too tired but otherwise you will.
So one way to say whether you’ll go is to say, you’ll go if you’re not broke or tired. Or in Java: !(broke || tired). (In English we hear β€œbroke or tired” as grouped together and both affected by the β€œnot”.)
But another way to say it is that you will go to the movies if you are not broke and you’re not tired. Or in Java: !broke && !tired. Thus !(broke || tired) and !broke && !tired are two different ways of saying the same thing.
By themselves De Morgan’s laws don’t usually lead to big simplifications but by giving us a way to flip && to || and vice versa, they can be a useful step toward rearranging a complex expression into a form where we can apply other rules to simplify it.
And they’re really great for answering AP exam questions that give you one boolean expression and ask you to pick out which of several others is equivalent to it.
We can also simplify negated boolean expressions involving comparison operators like <, >, and ==. And we can negate a comparison expression by flipping the comparison operator. For instance !(a == b) is flipped to a != b. The relational operators can be flipped either by swapping the operands (a < b becomes b < a) or by flipping the operator. But we need to remember which are the actual flipped operators. For < it is not > but >= and likewise for > and <=. In other words, to flip a comparison operator change the < or > to the other symbol and add an = if there isn’t one or remove it if there is.
Table 4.4.2. Negation of comparison expressions
Operator Flip operands Flip operator
a == b - a != b
a != b - a == b
a < b b < a a >= b
a <= b b <= a a > b
a > b b > a a <= b
a >= b b >= a a > b

Subsection 4.4.4 Truth tables

The other main technique for analyzing boolean expressions is called a truth table. Truth tables are a systematic way of analyzing the boolean expressions for all possible combinations values for the subexpressions.
For simple expressions a truth table can be used to spell out exactly what the values of that expression are. For instance, here are truth tables that show, in case you forgot, how &&, ||, and ! work.
a b a && b
false false false
false true false
true false false
true true true
Table 4.4.3. a && b truth table
a b a || b
false false false
false true true
true false true
true true true
Table 4.4.4. a || b truth table
a !a
false true
true false
Table 4.4.5. !a truth table
But we can also build truth tables for more complex expressions and if we build tables for two different expressions we can then compare the tables to determine whether the expressions are equivalent.
Building truth tables is a brute force approach which can be more tedious than doing a bit of Boolean algebra but doesn’t rely on any algebraic insight to figure out which rules to apply in order to manipulate one expression into the same form as the other. So if you are comfortable with them, you can always use them to grind out an analysis.
To build a truth table for an expression make at table with, initially, a column for each variable that occurs in the expression. Then add a column to the right for each subexpression, working back up to the whole expression. Each new column should be an expression that combines the expressions we have already made columns for using just one operator.
For instance to make a truth table for the expression !(a && b) we’d make a table with these columns.
a b a && b !(a && b)
Then add as many rows as there are different combinations of values for the variables. With two variables there are \(2^2\) or four combinations.
a b a && b !(a && b)
false false
false true
true false
true true
After that, it’s just a matter of filling in the columns, moving from left to right. Since each column is an expression in terms of one or two subexpressions whose column has already been filled in that should be easy.
Table 4.4.6. Truth table for !(a && b)
a b a && b !(a && b)
false false false true
false true false true
true false false true
true true true false
To determine if two expressions are equivalent, we can build truth tables for both expressions and then use the tables to check if for each combination of variable values the two expressions produce the same result. For instance, we can now build a table for !a || !b in order to show that De Morgan’s Law for && is true.
Table 4.4.7. Truth table for !a || !b
a b !a !b !a || !b
false false true true true
false true true false true
true false false true true
true true false false false
To compare the two tables, just look at the rightmost column of each and check that the values are the same for each now. (This assumes that you filled in the variabel combinations in the same order.) If they are, then the two expressions are equivalent. As you can see in those two tables the last column in both reads true, true, true, false so the expressions are equivalent.

Subsection 4.4.5 Summary

  • (AP 2.6.A.1) Two Boolean expressions are equivalent if they evaluate to the same value in all cases. Truth tables can be used to prove Boolean expressions are equivalent.
  • (AP 2.6.A.2) De Morgan’s Laws can be applied to Boolean expressions to create equivalent ones:
  • A negated expression with a relational operator can be simplified by flipping the relational operator to its opposite sign.
  • (AP 2.6.B.1) Two different variables can hold references to the same object. Object references can be compared using == and !=. (Two object references are considered aliases when they both reference the same object.)
  • (AP 2.6.B.2) An object reference can be compared with null, using == or !=, to determine if the reference actually references an object.
  • (AP 2.6.B.3) Classes often define their own equals method, which can be used to specify the criteria for equivalency for two objects of the class. The equivalency of two objects is most often determined using attributes from the two objects.

Subsection 4.4.6 AP Practice

Activity 4.4.1.

Which of the following best describes the value of the Boolean expression: a && !(b || a)?
  • The value is always true.
  • Try simplifying !(b ||a) or consider what happens if a and b are true.
  • The value is always false.
  • Yes, by applying De Morgan’s Law to !(b || a) we get that a && !(b || a) is equivalent to a && !b && !a. Since a && !a can never be true, the result will always be false.
  • The value is true when a has the value false, and is false otherwise.
  • Try the expression with a = false. Is the result true?
  • The value is true when b has the value false, and is false otherwise.
  • Try the expression with b = false with a = true and then try it with a = false. Is the result ever true?
  • The value is true when either a or b has the value true, and is false otherwise.
  • Try the expression with a = true. Is the result true?
You have attempted of activities on this page.