Skip to main content
Logo image

Section 4.3 Where do booleans come from?

In the previous section we discussed the different ways we could combine if statements to to make one-way, two-way, and multiway selection constructs. But in most of the examples we just assumed we had some boolean variable already set up to use in the conditions of our if statements.
But most of the logic that goes into making interesting algorithms comes from how we actually compute the boolean values that we use in if statements.
In this section we’ll look at the operators we can use to produce boolean values that don’t come from the literal boolean values we mentioned in the previous lesson. There are operators that produce boolean values from non-boolean values like int and double values and operators that we can use to combine boolean values to produce new boolean values.

Subsection 4.3.1 Comparison operators

In SubsectionΒ 2.3.1Β Basic arithmetic we learned about arithmetic operators like + and * that operate on numeric values to produce other numeric values. Now we need to learn about comparison operators that operate on numbers but produce boolean values. Comparison operators can be further divided into four relational operators that test ordering relationships between numbers and two equality operators which simply check whether two numbers are the same or different.
Table 4.3.1. Comparison operators
Name Written Value
Less than a < b true if a is less than b, false otherwise
Greater than a > b true if a is greater than b, false otherwise
Less than or equal a <= b true if a is less than or equal to b, false otherwise
Greater than or equal a >= b true if a is greater than or equal to b, false otherwise
Equals a == b true if a is the same value as b, false otherwise
Not equals a != b true if a and b are different values, false otherwise
The four relational operators (<, >, <=, >=) should be familiar from math class. Note however that due to the limitations of character sets traditionally used in programming languages, we write <= rather than ≀ and >= instead of β‰₯. To remember the correct order of the two characters in <= and >=, just write them in the same order you would say them in English: β€œless than or equal to” not β€œequal to or less than”.
If you need a refresher on these operators, one way to remember which is which is the hungry alligator mnemonic beloved by elementary school teachersβ€”think of < and > as the mouths of hungry alligators who always want to eat the bigger number; a < or > expression is only true if the open mouth of the alligator is about to chomp the bigger number. (With <= and >= the alligator is also okay if the number it’s going to eat is the same as the other number.)

Note 4.3.2.

In some programming languages comparison operators like < can be used to compare non-numeric values such as strings. But in Java they can only be used with numbers. As we’ll see in ChapterΒ 8Β Classes there are other ways to compare String values for both ordering and equality.

Activity 4.3.1.

Try to guess what the code below will print out before you run it. Then, set year to 15 and print the boolean expression for whether age is less than or equal to year.
The two equality operators (== and !=) are relatively straightforward. A couple things to note however, one is that they are both written with two characters. In particular the equality operator == is different than the assignment operator =. So if a and b are int values, a == b is a boolean expression, i.e. it’s value will be either true or false. But a = b is an int expression whose value will be the original value of b and will also have the side effect of assigning that value to a.
Unlike the relational operators, the equality operators can be used with any kinds of values, int, double, boolean as well as reference types like String and other types we’ll learn about later. But there are some subtleties to how they work with different kinds of values.
For int and boolean values, == and != are quite straightforward. Either two int values are the same or they are not. However, we will rarely use these operators with boolean values as doing so is usually unecessary and lead to a common mistake which we’ll discuss in SectionΒ 4.5Β if statement traps and pitfalls.
For String and other reference types we’ll discuss later, they β€œwork” but maybe not in the way you’d expect. We’ll discuss that in detail in SubsectionΒ 9.2.2Β Comparing Objects.
And finally, the equality operators should almost never be used with double values. They do work in the sense that if two double values are exactly the same, they will be ==. The problem is that because computers perform double math with limited precision, sometimes expressions that seem like they should produce mathematically equivalent results don’t produce exactly the same double values so even though they should be equal according to math they won’t be according to ==. One of the simplest examples is:
0.1 + 0.2 == 0.3 // evaluates to false!
You might wonder why these are different if double values can store up to 15 decimal places of precision! Understanding exactly why would involve getting into quite a lot of details about how double values are represented in memory that are well beyond the AP curriculum. But suffice it to say that this is a fact about how modern computers work, not a bug in Java. As a practical matter when doing double math, instead of comparing values for exact equality we should check whether the difference between two values is less than some meaningful threshold. For instance, if we were performing some computation on measurements in meters and wanted to check that the answer we got was β€œthe same” as some expected value, we might use an expression like the following to check that they are the same to a tenth of a millimeter:
Math.abs(computedMeters - expectedMeters) < 0.0001

Activity 4.3.2.

Activity 4.3.3.

What will the code below print out? Try to guess before you run it! Note that 1 equal sign (=) is used for assigning a value and 2 equal signs (==) for testing values. Then, add 3 more lines of code that sets year to 15 and prints out whether age is equal to year and whether age is not equal to year.

Subsection 4.3.2 Testing divisibility

A thing that comes up often enough in both real world coding and on the AP exam to be worth calling out is how to use the equality operators in combination with the remainder operator (%) to test whether int values are evenly divisible by other int values.
If a is evenly divisible by b, that just means that the remainder if you divide a by b is zero. So to check if a is evenly divisible by b (or is a multiple of b, which is another way to say the same thing) we can just write a % b == 0.
Table 4.3.3. Divisibility recipes
Expression Tests
number % 2 == 0 number is even
number % 2 != 0 number is odd.
number % x == 0 number is evenly divisible by x, a.k.a. number is a multiple of x

Note 4.3.4.

You might think you could check if a number was odd with the expression number % 2 == 1 rather than number % 2 != 0. However, because Java’s % operator is a remainder operator and not a true mathematical modulo operator, this won’t always work: when number is a negative odd number, number % 2 is -1 not 1. Thus you should always use number % 2 != 0 to check if number is odd.
Problems requiring use of % come up frequently on the AP exam. Keep it in mind for the following uses:
  • Checking whether a number is odd or even. If num % 2 != 0 then num is odd and if num % 2 == 0 then num is even.
  • Checking if a number is evenly divisible by any other number: If num1 % num2 == 0 is true then num1 is evenly divisible by num2.
  • Getting the last digit (one’s place) from an int: num % 10 gives us the rightmost digit of num.
  • Getting the number of minutes left when you convert a total number of minutes to hours and minutes:
    int totalMinutes = 345;
    int hours = totalMinutes / 60;   // Number of whole hours, i.e. 5
    int minutes = totalMinutes % 60; // Number of minutes left over, i.e. 45
    

Activity 4.3.4.

Try the expressions containing the % operator below to see how they can be used to check for even or odd numbers. All even numbers are divisible (with no remainder) by 2. Then, add another expression that tests to see if age1 is divisible by 3.

Subsection 4.3.3 Random probabilities

Another common way to want to produce boolean values is at random with some probability. This is quite easy since Math.random(), which we first saw in SectionΒ 3.3Β The Math class, returns a random number between 0.0 and 1.0 which is exactly how probabilities are usually expressed. (Zero probability means something definitely won’t happen; probability one means it definitely will.)
So we use Math.random() in combination with the < operator to write an expression that will be true with a given probability. For example, to simulate a coin flip, we can use the expression Math.random() < 0.5 which will be true with probability 0.5 or 50% of the time.
if (Math.random() < 0.5) {
    System.out.println("Heads");
} else {
    System.out.println("Tails");
}
More generally, for any probability p between zero and one, Math.random() < p will be true with that probability.
if (Math.random() < p) {
    System.out.println("Event happened");
} else {
    System.out.println("Event did not happen");
}
The easy way to remember that it should be < and not > or <= is to remember that Math.random() returns a number greater than or equal to 0.0 and less than 1.0. So Math.random() < 0.0 is never true Math.random() < 1.0 always is.

Activity 4.3.5. 40% chance.

Which of the following would be true about 40% of the time?
  • Math.random() < 0.4
  • This is true about 40% of the time since Math.random returns a value from 0 to not quite 1.
  • Math.random() > 0.4
  • This will be true about 60% of the time.
  • Math.random() == 0.4
  • Do not use == with double values! Remember that Math.random can return any number between 0 and not quite 1 (about .99999999).

Activity 4.3.6. 75% chance.

Which of the following would be true about 75% of the time?
  • Math.random() < 0.25
  • This is true about 25% of the time, since it will be a number from 0 to not quite 1.
  • Math.random() >= 0.25
  • This is true about 75% of the time, since it will be a number from 0 to not quite 1. Note that if the expression used > rather than >= it would be very slightly off. Generally it’s best to write this kind of expression with < and the probability of a true value so Math.random() < 0.75 in this case.
  • Math.random() == 0.25
  • Do not use == with double values! Remember that Math.random can return any number between 0 and not quite 1 (about .99999999).

Activity 4.3.7.

The weather report says there is approximately 25% chance of rain today. Which of the following if statements would print Rain or No Rain to simulate a day with the correct percentages following the weather report?
  • if (Math.random() < 0.25) { System.out.println("Rain"); }
    
  • Correct! This code will print β€œRain” 25% of the time.
  • if (Math.random() > 0.75) { System.out.println("Rain"); }
    
  • Correct. This code will print β€œRain” 25% (1 - .75) of the time.
  • if (Math.random() > 0.25) { System.out.println("Rain"); }
    
  • Incorrect. This code will print β€œRain” 75% of the time.
  • if (Math.random() < 0.75) { System.out.println("No Rain"); }
    
  • Correct! This code will print β€œNo Rain” 75% of the time, so it will rain 25% of the time.

Activity 4.3.8.

Add an if/else statement that uses Math.random() to do a coin flip to decide whether to call yertle.turnRight() or yertle.turnLeft. Run the code to see the turtle draw a random shape.

Subsection 4.3.4 Logical operators

The other set of operators in Java that produce boolean values are the logical operators. These operate on boolean values to produce new boolean values just like the arithmetic operators operate on numeric values and produce numeric values.
The three logical operators in Java come from Boolean algebra, a system for evaluating logical statements invented by George Boole, a 19th century English mathematician most famous for his book The Laws of Thought. These days we call these three operatarors logical and, logical or and logical not. And you are almost certainly already completely familiar with these operators and how they work even if you’ve never heard of George Boole.
For example, if you were looking for someone to share some chocolate ice cream with, you’d know that you need to find someone who likes ice cream and who also likes chocolate. A friend who likes ice cream but doesn’t like chocolate wouldn’t be interested. And another friend who likes chocolate but hates ice cream would also not be interested. If you understand that, you understand the logic of the situation which is expressed with logical and.
A logical and combines two statements like β€œlikes ice cream” and β€œlikes chocolate”, each of which is either true or false, into a new statement β€œlikes ice cream and likes chocolate” that is only true if both of the sub-statements are true.
In Java the logical and operator is written &&. Thus if we have two boolean expressions, such as two variables likesIceCream and likesChocolate, we can write an expression that combines them with &&:
likesIceCream && likesChocolate // true if, and only if, both variables are true
You already understand logical or if you understand that if need to get something off a high shelf that you can’t reach, you either need a tall friend or a step stool. You don’t need both a tall friend and a step stoolβ€”one or the other is fine. (Though if you did have both that would also work.) In Java we write logical or as ||:
haveTallFriend || haveStepStool // true if either, or both, variables are true

Note 4.3.5.

One place that the way we use β€œand” and β€œor” in English that doesn’t completely match with their sense in Boolean logic is when we use β€œor” to express a choice between two options when we can only pick one: β€œdo you want to be player 1 or player 2?” In Boolean logic and in Java the or operator is called an inclusive or which means that the whole expression is true if either one or the other or both conditions are true. Logically speaking there’s also an exclusive or which is true if either sub-statement is true but false if they both are. There isn’t a separate exclusive or operator in Java but != applied to boolean values serves as one.
a b a != b
false false false
false true true
true false true
true true false
Table 4.3.6. Truth table of != with boolean values
The final logical operator, logical not covers the logic of, β€œYou can go out if you’re not grounded”. If the statement β€œyou’re grounded” is true, then you can’t go out. But if the statement is false, then you can. In other words, logical not just flips the meaning of the statement, true to false and false to true. Logical not is written ! in Java and goes before the expression it operates on:
!grounded // true if grounded is false, false otherwise
You can say that !grounded is the logical negation of grounded, similar to how \(-4\) is the negation of \(4\text{.}\)

Activity 4.3.9. Can go out?

What if you want to go out and your parents say you can go out if you clean your room and do your homework? Run the code below and try different values for cleanedRoom and didHomework and see what they have to be for it to print You can go out.

Activity 4.3.10.

Suppose you want to go somewhere. You can go if you can walk there or if your parents aren’t using the car. Try different values for walking and carIsAvailable and see what the values have to be to print You can go out.

Activity 4.3.11.

The code below says if homework is not done, you can’t go out. Try different values for homeworkDone.

Subsection 4.3.5 Testing ranges

Just like we can use the == and % operators together to test whether numbers are divisible by other numbers, we can combine relational and logical operators to test whether a number is in a certain range.
In math we can write \(0 \le x \lt 100\) to express that \(x\) is in the range from zero (inclusive) to one hundred (exclusive). Unfortunately if we translate that directly to Java as 0 <= x < 100 we will get a compiler error. This is because 0 <= x produces a boolean which can’t then be an operand to the < operator. Instead we need to use && to combine two boolean expressions:
0 <= x && x < 100 // True if x is in range from 0 to 100, exclusive.
Less frequently we may want to write an expression that is true if a variable is not in a particular range. That’s as easy as applying a ! to the whole range expression. We need to put the range expression in parentheses because ! has very high precedence.
!(0 <= x && x < 100) // True if x is outside the range from 0 to 100, exclusive.
We could also write that in this logically equivalent way:
x < 0 || x >= 100

Activity 4.3.12.

Explore how && and || are used with numbers below. Try different values for score like -10 and 110 in the code below.

Subsection 4.3.6 Short Circuit Evaluation

Both && and || use short circuit evaluation. That means that the second expression (on the right of the operator) isn’t necessarily checked, if the result from the first expression is enough to tell if the compound boolean expression is true or false:
  • If two boolean values/expressions are combined with a logical or (||) and the first expression is true, then the second expression won’t be executed, since only one needs to be true for the result to be true.
  • If two boolean values/expressions are combined with a logical and (&&) and the first expression is false, then the second expression won’t be executed. If the first expression is false, the result will be false, since both sides of the && need to be true for the result to be true.

Activity 4.3.13.

What is printed when the following code executes and x has been set to 0 and y to 3?
if (x > 0 && (y / x) == 3)
{
   System.out.println("first case");
}
else
{
   System.out.println("second case");
}
  • first case
  • first case will only print if x is greater than 0 and it is not.
  • second case
  • second case will print if x is less than or equal to zero or if y divided by x is not equal to 3.
  • You will get a error because you can’t divide by zero.
  • Since the first condition is false when x is equal to zero the second condition won’t execute. Execution moves to the else.

Activity 4.3.14.

What is printed when the following code executes and x has been set to zero and y is set to 3?
if (x == 0 || (y / x) == 3)
{
   System.out.println("first case");
}
else
{
   System.out.println("second case");
}
  • first case
  • Since x is equal to zero the first expression in the complex conditional will be true and the (y / x) == 3 won’t be evaluated, so it won’t cause a divide by zero error. It will print "first case".
  • second case
  • Since x is equal to zero the first part of the complex conditional is true so it will print first case.
  • You will get a error because you can’t divide by zero.
  • You won’t get an error because of short circuit evaluation. The (y / x) == 3 won’t be evaluated since the first expression is true and an or is used.

Subsection 4.3.7 Summary

  • (AP 2.2.A.1) Values or expressions can be compared using the relational operators == and != to determine whether the values are the same. With primitive types, this compares the actual primitive values. With reference types, this compares the object references.
  • (AP 2.2.A.2) Numeric values or expressions can be compared using the relational operators (<, >, <=, >=) to determine the relationship between the values.
  • (AP 2.2.A.3) An expression involving relational operators evaluates to a Boolean value of true or false.
  • The remainder operator % can be used to test for divisibility by a number. For example, num % 2 == 0 can be used to test if a number is even.
  • (AP 2.5.A.1) Logical operators ! (not), && (and), and || (or) are used with Boolean values.
  • (AP 2.5.A.1) ! has precedence (is executed before) && which has precedence over ||. (Parentheses can be used to force the order of execution in a different way.)
  • (AP 2.5.A.1) An expression involving logical operators evaluates to a Boolean value.
  • (AP 2.5.A.2) Short-circuit evaluation occurs when the result of a logical operation using && or || can be determined by evaluating only the first Boolean expression. In this case, the second Boolean expression is not evaluated. (If the first expression is true in an || operation, the second expression is not evaluated since the result is true. If the first expression is false in an && operation, the second expression is not evaluated since the result is false.)

Subsection 4.3.8 AP Practice

Activity 4.3.15.

Consider the following statement.
boolean x = (5 % 3 == 0) == (3 > 5);
What is the value of x after the statement has been executed?
  • false
  • Although both sides of the middle == are false, false == false is true! Tricky!
  • (5 % 3 == 0) is false and (3 > 5) is false, and false == false is true! Tricky!
  • (5 % 3 == 0)
  • The boolean x should hold true or false.
  • (3 > 5)
  • The boolean x should hold true or false.
  • The boolean x should hold true or false.

Activity 4.3.16.

Consider the following Boolean expression in which the int variables x and y have been properly declared and initialized.
(x >= 10) == (y < 12)
Which of the following values for x and y will result in the expression evaluating to true ?
  • x = 10 and y = 12
  • The left side is true, but y must be less than 12 to make the right side true.
  • x = 9 and y = 9
  • The left side is false (x must be greater than or equal to 10), but the right side is true.
  • x = 10 and y = 11
  • Correct! Both sides are true!
  • x = 10 and y = 13
  • The left side is true, but y must be less than 12 to make the right side true.
  • x = 9 and y = 12
  • Correct! Both sides are false! This is tricky!

Activity 4.3.17.

Consider the following code segment. What is printed as a result of executing the code segment?
int x = 10;
int y = 5;

if (x % 2 == 0 && y % 2 == 0 || x > y)
{
    System.out.print("First ");

    if (y * 2 == x || y > 5 && x <= 10)
    {
       System.out.print("Second ");
    }
    else
    {
       System.out.print("Third ");
    }
}
  • Nothing is printed out.
  • Some of these conditions are true.
  • First
  • This is partially correct.
  • Third
  • Third cannot be printed out unless First is printed out first.
  • First Second
  • Good tracing!
  • First Third
  • Take another look at the second condition.
You have attempted of activities on this page.