Skip to content
HopperHopper

Course navigation

Unit 2 · Selection and IterationTopic 2.9

Implementing Selection and Iteration Algorithms

  • About 60 minutes
  • 6 sections
  • Runnable Java examples
  • Practice questions

Before you start

About 60 minutes

By the end you will be able to

  1. Trace and explain the standard loop patterns for adding up a sum and computing an average.
  2. Count how many values meet a condition by putting an if statement inside a loop.
  3. Use the remainder operator to decide whether one integer divides another evenly.
  4. Pull an integer apart into its digits with % 10 and / 10 inside a while loop.
  5. Find the smallest or largest value in a series and explain how the starting value affects the result.
  6. Combine these patterns to predict the output of a longer program and to find and fix bugs in it.

What to remember from earlier

Section 1 of 6

2.9.1 Adding Up a Sum

You now have every building block you need to make a program decide (if statements) and repeat (while and for loops). This topic is about putting those blocks together to solve problems that come up again and again: What is the total of these prices? What is the average score? How many days were hot? What was the coldest night? Programmers solve these so often that each has a well-known shape. A standard algorithm is a step-by-step solution to a common problem that programmers reuse, adjusting the details each time. Once you recognize the shape, you can read, trace, and fix code that uses it quickly, and you can combine shapes to solve new problems.

The first and most common problem is adding up a series of numbers. Think about how you add a stack of receipts by hand. You do not look at all of them at once. You start at zero, look at one receipt, add its amount to what you have so far, then move to the next receipt and add again. The number in your head is a running total: the sum of every value you have looked at so far.

A program does the same thing with a variable. An accumulator is a variable that collects a result a little at a time as a loop runs; when the result is a sum, the accumulator holds the running total. Every sum algorithm has the same three parts:

Part Code Why it is there
Start the total at zero int total = 0; Before you have looked at anything, the sum is zero. Done before loop.
Add one value on each pass total += value; Each pass makes the running total include one more value. Done inside.
Use the total after the loop println(total) Only when the loop has finished does the total include every value.

The order matters. The total must be set to zero once, before the loop starts, so that the additions on later passes are not thrown away. The += from Topic 1.6 does the adding: total += value; means total = total + value;, so each pass builds on what the earlier passes stored.

Key idea

To add up a series of values, start an accumulator at 0 before the loop, add one value to it with += on each pass, and use the finished total after the loop ends.

Worked example: Adding the numbers 1 through 5

Here the values to add come from the loop control variable itself, which counts 1, 2, 3, 4, 5. Watch total grow by the current value of number on each pass.

int total = 0;
for (int number = 1; number <= 5; number++)
{
    total += number;
}
System.out.println(total);

Line 1 runs once. Then the for loop from Topic 2.8 takes over: it sets number to 1, checks number <= 5, runs the body (line 4), updates number, and checks again.

Pass number total before line 4 total after line 4
1 1 0 1
2 2 1 3
3 3 3 6
4 4 6 10
5 5 10 15

After pass 5, number becomes 6, the condition 6 <= 5 is false, and the loop ends. Line 6 prints:

15

Read the “before” column: each pass starts from exactly what the pass before it stored. That is why the total ends up as 1 + 2 + 3 + 4 + 5.

Now change where the values come from. Without lists of data (those come in Unit 4), a program usually gets a series of values by reading them one at a time. This example reads them with a Scanner. The first number in the input says how many prices follow, so a for loop can run exactly that many times. A keyboard Scanner would work the same way; this guide builds the Scanner from a string so the output is always the same.

Worked example: Totaling a receipt

ReceiptTotal.java
import java.util.Scanner;

public class ReceiptTotal
{
    public static void main(String[] args)
    {
        Scanner input = new Scanner("4 3.25 1.50 2.75 4.00");
        int itemCount = input.nextInt();
        double total = 0.0;
        for (int item = 1; item <= itemCount; item++)
        {
            double price = input.nextDouble();
            total += price;
        }
        System.out.print("Total: ");
        System.out.println(total);
    }
}

Line 8 reads 4, the number of items. Line 9 starts the accumulator at 0.0; it is a double because prices have decimal parts. On each pass, line 12 reads the next price into price, and line 13 adds it to total.

item price read on line 12 total after line 13
1 3.25 3.25
2 1.5 4.75
3 2.75 7.5
4 4.0 11.5

When item becomes 5, the condition 5 <= 4 is false. Lines 15 and 16 print:

Total: 11.5

Compare this with the first example. The loop and the accumulator have the same shape; only the source of each value changed, from the loop control variable to input.nextDouble(). Notice too that price is replaced on every pass, while total keeps growing. A variable that holds “the current value” and a variable that holds “the result so far” play very different roles.

Watch out

Resetting the total inside the loop. Students sometimes put the “start at zero” step inside the loop, thinking each pass needs a fresh start:

int total = 0;
for (int number = 1; number <= 5; number++)
{
    total = 0;
    total += number;
}
System.out.println(total);

This prints 5, not 15. On every pass, line 4 wipes out the running total and line 5 adds only the current number. After the last pass, total holds just 0 + 5. Java gives no error, because setting a variable to zero is legal; the program simply answers a different question. The fix is to set the total to zero once, before the loop, as in the first worked example.

Pause and try

Question 1 · Tracing

What does this code print? Make a trace table with columns for k and total.

int total = 0;
for (int k = 3; k <= 12; k += 3)
{
    total += k;
}
System.out.println(total);
Check your reasoning

It prints 30.

k total after line 4
3 3
6 9
9 18
12 30

The update k += 3 makes k jump by threes, so the loop adds 3 + 6 + 9 + 12. After the pass with k equal to 12, k becomes 15, and 15 <= 12 is false, so the loop stops. If you got 18, you stopped before 12; the condition uses <=, so 12 itself is included.

Reread 2.9.1 Adding Up a Sum if your answer differed.

Question 2 · Debugging

This code is supposed to print the sum of the whole numbers from 1 through 10, which is 55. It prints 45 instead. Find the error and correct it.

int total = 0;
for (int number = 1; number < 10; number++)
{
    total += number;
}
System.out.println(total);
Check your reasoning

The condition on line 2 should be number <= 10:

for (int number = 1; number <= 10; number++)

With number < 10, the loop stops as soon as number reaches 10, so 10 is never added: 1 + 2 + … + 9 is 45. This is an off-by-one error from Topic 2.7: the loop runs one time too few. With <=, the last pass adds 10 and the program prints 55. The accumulator part of the code was already correct; only the loop’s range was wrong.

Reread 2.9.1 Adding Up a Sum if your answer differed.

Section 2 of 6

2.9.2 Computing an Average

A teacher does not usually want the total of a class’s quiz scores; she wants the average. A weather report gives the average rainfall, not the sum. To find an average (also called the mean), you add up the values and divide by how many values there are. So an average algorithm is the sum algorithm from 2.9.1 plus one division after the loop.

The division is where things go wrong, because of a rule from Topic 1.3: when both numbers are int, / throws away the decimal part. A sum of whole-number scores and a count of scores are both int, so sum / count can lose information. The fix, from Topic 1.5, is to cast one of them to double before dividing, so the division is done with decimals.

Key idea

An average is the sum divided by the number of values. When both are int, write (double) sum / count so the division keeps its decimal part.

Worked example: Average rainfall over five days

The first input value is the number of days. Each pass of the loop reads one day’s rainfall and adds it straight into the accumulator. Line 12 passes the value from nextInt() directly to +=; no separate variable is needed when the value is used only once.

RainfallAverage.java
import java.util.Scanner;

public class RainfallAverage
{
    public static void main(String[] args)
    {
        Scanner input = new Scanner("5 12 7 0 9 4");
        int days = input.nextInt();
        int totalRain = 0;
        for (int day = 1; day <= days; day++)
        {
            totalRain += input.nextInt();
        }
        double average = (double) totalRain / days;
        System.out.print("Average rainfall: ");
        System.out.println(average);
    }
}
day Value read totalRain after line 12
1 12 12
2 7 19
3 0 19
4 9 28
5 4 32

After the loop, line 14 computes the average. The cast applies only to totalRain, the value right after it, and it happens before the division. So Java works out 32.0 / 5, a double divided by an int, which is 6.4:

Average rainfall: 6.4

Day 3 had no rain, but it still counts as a day. The value 0 adds nothing to the total, yet the division is still by 5.

Where the cast goes matters. This snippet tries three ways with the same total and count:

int totalRain = 32;
int days = 5;
System.out.println(totalRain / days);
System.out.println((double) (totalRain / days));
System.out.println((double) totalRain / days);
6
6.0
6.4
Expression What Java does Result
totalRain / days int divided by int: decimal part dropped. 6
(double) (totalRain / days) Parentheses first: 32 / 5 is 6; then cast. 6.0
(double) totalRain / days Cast first: 32.0 / 5 is a double division. 6.4

The middle one is the trap. It looks like it uses a cast, but by the time the cast happens, the integer division has already thrown away the .4. Casting 6 to a double gives 6.0, not 6.4.

So far the program knew how many values were coming. Often it does not: a teacher types scores until she is done. You met the usual way to handle this in Topic 2.7: a sentinel value, a special value that is not real data and that means “stop reading.” Quiz scores are never negative, so -1 works as a sentinel. Because the program does not know in advance how many values there will be, it uses a while loop (Topic 2.7) and a second accumulator. A counter is an accumulator that adds one each time something happens; here it adds one for each real value read.

Worked example: Average quiz score with a sentinel

QuizAverage.java
import java.util.Scanner;

public class QuizAverage
{
    public static void main(String[] args)
    {
        Scanner input = new Scanner("88 92 75 90 -1");
        int sum = 0;
        int count = 0;
        int score = input.nextInt();
        while (score != -1)
        {
            sum += score;
            count++;
            score = input.nextInt();
        }
        if (count > 0)
        {
            double average = (double) sum / count;
            System.out.print("Average: ");
            System.out.println(average);
        }
        else
        {
            System.out.println("No scores");
        }
    }
}

The reading pattern has a special shape. Line 10 reads the first value before the loop, so the condition on line 11 has something to check. Inside the loop, line 15 reads the next value last, so the condition checks each new value before it is added.

Step score sum count
Line 10 reads 88 0 0
Pass 1 (lines 13–15) 92 88 1
Pass 2 75 180 2
Pass 3 90 255 3
Pass 4 -1 345 4

The score column shows the value read at the end of each pass. After pass 4, score is -1, so score != -1 is false and the loop ends. The -1 is never added, which is the whole point of a sentinel. Line 19 computes 345.0 / 4:

Average: 86.25

The if on line 17 guards the division. If the very first value were -1, the loop body would never run (Topic 2.7), count would still be 0, and there would be nothing to average. With input "-1" this program prints No scores instead.

Watch out

Dividing when there are no values. Without the count > 0 check, an empty input means dividing by zero. Here is a version that uses int division and no guard:

AverageNoGuard.java
import java.util.Scanner;

public class AverageNoGuard
{
    public static void main(String[] args)
    {
        Scanner input = new Scanner("-1");
        int sum = 0;
        int count = 0;
        int score = input.nextInt();
        while (score != -1)
        {
            sum += score;
            count++;
            score = input.nextInt();
        }
        int average = sum / count;
        System.out.println(average);
    }
}

The loop never runs, so line 17 tries 0 / 0 and the program crashes:

Exception in thread "main" java.lang.ArithmeticException: / by zero
	at AverageNoGuard.main(AverageNoGuard.java:17)

(The exact wording can vary between Java versions.) With the (double) cast it would instead be a double divided by zero, a case this course leaves out. Either way there is no meaningful average, so the fix is the same: check that count > 0 before dividing, as QuizAverage.java does.

Pause and try

Question 3 · Multiple choice

The int variables total and count hold 17 and 4. Which expression evaluates to 4.25?

  1. total / count
  2. (double) (total / count)
  3. (double) total / count
  4. (int) ((double) total / count)
Check your reasoning

C. The cast turns total into 17.0 before the division, so Java divides a double by an int and keeps the decimal part: 17.0 / 4 is 4.25.

  • A is wrong: both values are int, so the division drops the decimal part and gives 4.
  • B is wrong: the parentheses make 17 / 4 happen first, which is already 4; casting afterward gives 4.0.
  • D is wrong: the inside correctly computes 4.25, but the outer (int) cast then chops off the decimal part, giving 4.

Reread 2.9.2 Computing an Average if you chose differently.

Question 4 · Tracing

What does this program print? Trace score, sum, and count.

SentinelZeroScore.java
import java.util.Scanner;

public class SentinelZeroScore
{
    public static void main(String[] args)
    {
        Scanner input = new Scanner("10 0 5 -1");
        int sum = 0;
        int count = 0;
        int score = input.nextInt();
        while (score != -1)
        {
            sum += score;
            count++;
            score = input.nextInt();
        }
        System.out.println((double) sum / count);
    }
}
Check your reasoning

It prints 5.0.

Step score sum count
Line 10 reads 10 0 0
Pass 1 0 10 1
Pass 2 5 10 2
Pass 3 -1 15 3

The 0 is a real score, not the sentinel: the loop stops only at -1. So the 0 is counted, even though it adds nothing to the sum. Then (double) 15 / 3 is 5.0. If you got 7.5, you skipped the 0 and divided by 2.

Reread 2.9.2 Computing an Average if your answer differed.

Section 3 of 6

2.9.3 Counting Values That Meet a Condition

In 2.9.2 you counted every value. Often you need to count only some of them. How many days this week were over 90 degrees? How many students scored in the B range? How many numbers from 1 to 100 are even? Each question asks for a frequency: the number of times a particular condition is true.

The plan is the counter from the average algorithm, which added one for every value, with an if statement wrapped around the count++. Start it at 0 before the loop. Inside the loop, test the current value; only when the condition is true, add one.

int count = 0;
// loop over the values:
    if (condition about the current value)
    {
        count++;
    }
// after the loop, count holds the answer

Why 0 and not 1? Before the loop has checked anything, no value has met the condition. Starting at 1 would claim one match before seeing any data.

Key idea

To count how often a condition is met, start a counter at 0 before the loop, and inside the loop add one only when an if statement finds the condition true.

Worked example: Counting hot days

The input holds seven daily high temperatures. A day is “hot” when its high is above 90.

HotDays.java
import java.util.Scanner;

public class HotDays
{
    public static void main(String[] args)
    {
        Scanner input = new Scanner("7 88 93 91 79 95 90 84");
        int days = input.nextInt();
        int hotCount = 0;
        for (int day = 1; day <= days; day++)
        {
            int temp = input.nextInt();
            if (temp > 90)
            {
                hotCount++;
            }
        }
        System.out.print("Hot days: ");
        System.out.println(hotCount);
    }
}
day temp temp > 90? hotCount after the if
1 88 false 0
2 93 true 1
3 91 true 2
4 79 false 2
5 95 true 3
6 90 false 3
7 84 false 3
Hot days: 3

Look at day 6. A high of exactly 90 is not “above 90,” so 90 > 90 is false and the counter does not change. If the question had been “at least 90,” the condition would be temp >= 90 and the answer would be 4. The counting pattern never changes; the condition decides what is counted, so read it carefully at the boundary.

The condition can be anything you learned in Topics 2.2 through 2.6, including compound conditions. Here the question is how many scores fall from 70 to 89, including both ends.

Worked example: Counting scores in a range

ScoreBand.java
import java.util.Scanner;

public class ScoreBand
{
    public static void main(String[] args)
    {
        Scanner input = new Scanner("6 72 95 89 64 70 90");
        int students = input.nextInt();
        int inBand = 0;
        for (int student = 1; student <= students; student++)
        {
            int score = input.nextInt();
            if (score >= 70 && score <= 89)
            {
                inBand++;
            }
        }
        System.out.print("Scores from 70 to 89: ");
        System.out.println(inBand);
    }
}

A score is in the range only when it is at least 70 and at most 89, so line 13 joins two comparisons with && (Topic 2.5).

score score >= 70 score <= 89 Counted?
72 true true yes (1)
95 true false no
89 true true yes (2)
64 false (skipped) no
70 true true yes (3)
90 true false no
Scores from 70 to 89: 3

For 64, the first comparison is false, so && short-circuits and never checks the second (Topic 2.5); the whole condition is already false. Both 70 and 89 count because the comparisons use >= and <=.

Watch out

Leaving out the braces. As in Topic 2.3, without braces an if controls only the one statement right after it, no matter how the lines are indented. Here a student wanted to print each hot temperature and count it:

HotDaysNoBraces.java
import java.util.Scanner;

public class HotDaysNoBraces
{
    public static void main(String[] args)
    {
        Scanner input = new Scanner("7 88 93 91 79 95 90 84");
        int days = input.nextInt();
        int hotCount = 0;
        for (int day = 1; day <= days; day++)
        {
            int temp = input.nextInt();
            if (temp > 90)
                System.out.println(temp);
                hotCount++;
        }
        System.out.print("Hot days: ");
        System.out.println(hotCount);
    }
}
93
91
95
Hot days: 7

The prints are right, but the count is 7, the number of days, not the number of hot days. Only line 14 belongs to the if. Line 15 is indented to look as if it belongs, but Java ignores indentation, so hotCount++ runs on every pass. The fix is to put braces around both statements so that both are inside the if:

if (temp > 90)
{
    System.out.println(temp);
    hotCount++;
}

Pause and try

Question 5 · Tracing

What two numbers does this program print?

FreezeCount.java
import java.util.Scanner;

public class FreezeCount
{
    public static void main(String[] args)
    {
        Scanner input = new Scanner("5 32 15 40 32 28");
        int nights = input.nextInt();
        int freezing = 0;
        int aboveFreezing = 0;
        for (int night = 1; night <= nights; night++)
        {
            int temp = input.nextInt();
            if (temp <= 32)
            {
                freezing++;
            }
            else
            {
                aboveFreezing++;
            }
        }
        System.out.println(freezing);
        System.out.println(aboveFreezing);
    }
}
Check your reasoning

It prints 4 and then 1.

temp temp <= 32? freezing aboveFreezing
32 true 1 0
15 true 2 0
40 false 2 1
32 true 3 1
28 true 4 1

The if-else adds one to exactly one of the two counters on every pass, so the two counts always add up to the number of nights, 5. Both 32s count as freezing because the condition is <=. If you got 2 and 3, you treated 32 as above freezing.

Reread 2.9.3 Counting Values That Meet a Condition if your answer differed.

Question 6 · Multiple choice

In ScoreBand.java, the scores were 72, 95, 89, 64, 70, and 90. Which condition on line 13 would count exactly the scores outside the range 70 to 89, giving a count of 3?

  1. score < 70 && score > 89
  2. score < 70 || score > 89
  3. score <= 70 || score >= 89
  4. !(score > 70 && score < 89)
Check your reasoning

B. A score is outside the range when it is below 70 or above 89. That matches 95, 64, and 90, for a count of 3.

  • A is wrong: no number can be below 70 and above 89 at the same time, so the condition is never true and the count is 0.
  • C is wrong: <= and >= also match the boundary scores 70 and 89, which are inside the range. The count is 5.
  • D is wrong for the same reason. By De Morgan’s law (Topic 2.6) it means score <= 70 || score >= 89, the same as C, so it also counts 5.

Reread 2.9.3 Counting Values That Meet a Condition if you chose differently.

Section 4 of 6

2.9.4 Testing Whether One Integer Divides Another

Can 84 marbles be shared equally among 7 friends with none left over? Is this year a multiple of 4? Is a number even? All of these ask whether one integer is evenly divisible by another: dividing leaves a remainder of zero.

You already have the tool. From Topic 1.3, a % b gives the remainder when a is divided by b. If the remainder is 0, then b goes into a exactly. So the test “is a evenly divisible by b?” is the Boolean expression

a % b == 0

and “is a not evenly divisible by b?” is a % b != 0. In this course, the number being divided is never negative and the number you divide by is always positive, so these are the only cases you need.

Key idea

a % b == 0 is true exactly when a is evenly divisible by b.

Worked example: Sharing marbles

int marbles = 84;
int friends = 7;
System.out.println(marbles % friends);
if (marbles % friends == 0)
{
    System.out.println("7 friends: shares evenly");
}
friends = 5;
System.out.println(marbles % friends);
if (marbles % friends == 0)
{
    System.out.println("5 friends: shares evenly");
}
else
{
    System.out.println("5 friends: some left over");
}
0
7 friends: shares evenly
4
5 friends: some left over

Line 3 prints 84 % 7. Seven goes into 84 exactly twelve times (7 × 12 = 84), so the remainder is 0 and the condition on line 4 is true. After line 8 changes friends to 5, line 9 prints 84 % 5: five goes into 84 sixteen times (80), leaving 4. The condition on line 10 is false, so the else runs.

The most common divisibility test is checking whether a number is even, which means “divisible by 2.” Every whole number leaves a remainder of either 0 or 1 when divided by 2:

for (int n = 6; n <= 9; n++)
{
    System.out.print(n);
    System.out.print(" % 2 is ");
    System.out.println(n % 2);
}
6 % 2 is 0
7 % 2 is 1
8 % 2 is 0
9 % 2 is 1

So n % 2 == 0 means n is even, and n % 2 != 0 means n is odd.

A divisibility test becomes much more powerful inside a loop. Combine it with the counting pattern from 2.9.3, and you can find every number that divides another.

Worked example: Finding the divisors of 12

A divisor of a number is a whole number that divides it evenly. This loop tries every candidate d from 1 up to the number itself and keeps the ones that leave no remainder.

int number = 12;
int divisorCount = 0;
for (int d = 1; d <= number; d++)
{
    if (number % d == 0)
    {
        System.out.print(d);
        System.out.print(" ");
        divisorCount++;
    }
}
System.out.println();
System.out.print("Divisors: ");
System.out.println(divisorCount);
d 12 % d Divisor? divisorCount
1 0 yes 1
2 0 yes 2
3 0 yes 3
4 0 yes 4
5 2 no 4
6 0 yes 5
7–11 not 0 no 5
12 0 yes 6

Each divisor is printed with a space after it on one line, and line 12 then ends that line:

1 2 3 4 6 12
Divisors: 6

Change only number to 13 and the same code prints 1 13 and Divisors: 2. A number greater than 1 whose only divisors are 1 and itself is called a prime number, so this one loop can also tell you whether a number is prime: it is prime exactly when the count is 2.

Watch out

Writing the two numbers in the wrong order. “84 is divisible by 7” puts 84 first, so the test is 84 % 7 == 0. It is easy to swap them:

int marbles = 84;
int friends = 7;
System.out.println(friends % marbles);
if (friends % marbles == 0)
{
    System.out.println("Shares evenly");
}
else
{
    System.out.println("Some left over");
}
7
Some left over

friends % marbles is 7 % 84. Since 84 does not go into 7 even once, the whole 7 is left over, so the remainder is 7 and the test fails. Read a % b == 0 as “a divided by b leaves nothing,” with the bigger whole (the thing being shared) on the left. The fix is marbles % friends == 0.

Pause and try

Question 7 · Debugging

This code is supposed to count the even numbers from 1 to 10, which should be 5. It prints 1. Find the error and correct it.

int evenCount = 0;
for (int n = 1; n <= 10; n++)
{
    if (n / 2 == 0)
    {
        evenCount++;
    }
}
System.out.println(evenCount);
Check your reasoning

Line 4 uses / where it needs %. The corrected line is:

if (n % 2 == 0)

n / 2 is the integer quotient, not the remainder. It is 0 only when n is 1 (because 1 / 2 is 0 in integer division), so the counter goes up only once. n % 2 is the remainder, which is 0 exactly for 2, 4, 6, 8, and 10. With the fix the program prints 5.

Reread 2.9.4 Testing Whether One Integer Divides Another if your answer differed.

Question 8 · Multiple choice

What does this code print?

for (int n = 1; n <= 30; n++)
{
    if (n % 4 == 0 && n % 6 == 0)
    {
        System.out.println(n);
    }
}
  1. 12 and 24, each on its own line
  2. 4, 6, 8, 12, 16, 18, 20, 24, 28, and 30, each on its own line
  3. 24 only
  4. Nothing
Check your reasoning

A. With &&, a number is printed only when it is divisible by 4 and by 6. From 1 to 30, the multiples of 4 are 4, 8, 12, 16, 20, 24, 28, and the multiples of 6 are 6, 12, 18, 24, 30. The numbers in both lists are 12 and 24.

  • B is wrong: that list is every number divisible by 4 or 6, which is what || would print.
  • C is wrong: 24 = 4 × 6, but 12 is also divisible by both (12 = 4 × 3 = 6 × 2). Do not assume the first common multiple is the product.
  • D is wrong: the loop reaches 12 and 24, and both pass the test.

Reread 2.9.4 Testing Whether One Integer Divides Another if you chose differently.

Section 5 of 6

2.9.5 Pulling Apart the Digits of an Integer

A credit card number has a check digit that catches typos. A puzzle asks for the sum of the digits of a number. A program reports how many digits a number has. Each needs the individual digits of an int, but an int is a single number, not a row of separate digits. How do you get at them?

The answer uses the two kinds of integer division from Topic 1.3, with 10:

  • number % 10 is the last digit (the ones digit). Dividing by 10 leaves the ones digit as the remainder: 4072 % 10 is 2.
  • number / 10 drops the last digit. Integer division by 10 throws away the ones digit: 4072 / 10 is 407.

Why 10? Our numbers are written in base ten: each place is worth ten times the place to its right. Dividing by 10 shifts every digit one place to the right, and whatever falls off the end is the remainder. You can combine the two to reach any digit:

int number = 4072;
System.out.println(number % 10);
System.out.println(number / 10);
System.out.println(number / 10 % 10);
System.out.println(number / 100 % 10);
Line Expression Work Result
2 number % 10 ones digit of 4072 2
3 number / 10 drop the 2 407
4 number / 10 % 10 407 % 10 (tens digit) 7
5 number / 100 % 10 40 % 10 (hundreds) 0

Line 4 has no parentheses but still works left to right: / and % have the same precedence, so number / 10 happens first and % 10 is applied to its result.

To visit every digit without knowing how many there are, put the two steps in a while loop: take the last digit, then drop it, and repeat until nothing is left. When the number reaches 0, every digit has been removed.

Key idea

number % 10 gives the last digit and number / 10 removes it. Repeating both in a while (number > 0) loop visits every digit, from right to left.

Worked example: Printing the digits of 4072

int number = 4072;
while (number > 0)
{
    int digit = number % 10;
    System.out.println(digit);
    number = number / 10;
}
Pass number at start digit (line 4) number after line 6
1 4072 2 407
2 407 7 40
3 40 0 4
4 4 4 0
2
7
0
4

After pass 4, number is 0, so 0 > 0 is false and the loop ends. The digits come out right to left, because % 10 always takes the rightmost one. Notice that the zero in the middle is found like any other digit. Line 6 is what moves the loop toward ending; if it were missing, number would stay 4072 forever and number > 0 would always be true, an infinite loop (Topic 2.7).

Because the loop destroys the number as it goes, a program that still needs the original value copies it first. This next example does that and uses two accumulators at once: a sum of the digits and a count of the digits.

Worked example: Adding and counting the digits of 9035

int number = 9035;
int remaining = number;
int digitSum = 0;
int digitCount = 0;
while (remaining > 0)
{
    digitSum += remaining % 10;
    digitCount++;
    remaining /= 10;
}
System.out.print(number);
System.out.print(" has ");
System.out.print(digitCount);
System.out.print(" digits that add up to ");
System.out.println(digitSum);
remaining at start remaining % 10 digitSum digitCount
9035 5 5 1
903 3 8 2
90 0 8 3
9 9 17 4
9035 has 4 digits that add up to 17

The loop changes only remaining, so number still holds 9035 when lines 11 to 15 print it. Line 9 uses /= from Topic 1.6; remaining /= 10; means the same as remaining = remaining / 10;.

These digit algorithms assume the number is not negative. That is the usual situation (counts, years, ID numbers), and the remainder operator with negative numbers is outside this course.

Watch out

Forgetting the number 0. How many digits does 0 have? One. But the digit-counting loop says zero:

int number = 0;
int digitCount = 0;
while (number > 0)
{
    digitCount++;
    number /= 10;
}
System.out.println(digitCount);

This prints 0. The condition 0 > 0 is false the very first time, so the body never runs (Topic 2.7). The loop is correct for every positive number but misses this edge case. One fix is to handle 0 separately with an if before the loop:

int number = 0;
int digitCount = 0;
if (number == 0)
{
    digitCount = 1;
}
while (number > 0)
{
    digitCount++;
    number /= 10;
}
System.out.println(digitCount);

This prints 1. For any positive number, the if is skipped and the loop counts as before.

Pause and try

Question 9 · Tracing

What does this code print?

int n = 615;
while (n > 0)
{
    System.out.print(n % 10);
    n /= 10;
}
System.out.println();
Check your reasoning

It prints 516 on one line.

n at start n % 10 printed n after line 5
615 5 61
61 1 6
6 6 0

print keeps everything on one line, and the digits come out right to left, so the number appears reversed. Line 7 then ends the line. If you got 615, you printed the digits left to right; % 10 always gives the rightmost digit first.

Reread 2.9.5 Pulling Apart the Digits of an Integer if your answer differed.

Question 10 · Multiple choice

The int variable n holds 4729. Which expression evaluates to the hundreds digit, 7?

  1. n % 100
  2. n / 100
  3. n / 100 % 10
  4. n % 10 / 100
Check your reasoning

C. n / 100 drops the last two digits, giving 47; then % 10 takes the last digit of that, 7.

  • A is wrong: % 100 keeps the last two digits, 29.
  • B is wrong: it gives 47, which still has the thousands digit in front.
  • D is wrong: n % 10 is 9, and 9 / 100 is 0 in integer division.

Reread 2.9.5 Pulling Apart the Digits of an Integer if you chose differently.

Section 6 of 6

2.9.6 Finding the Minimum or Maximum

Which player had the highest score? What was the coldest night of the week? These ask for the maximum (largest value) or the minimum (smallest value) in a series.

Think about how you would find the tallest person in a line if you could see only one person at a time. You would remember the tallest person so far. You look at the first person: so far, they are the tallest. For each next person, you compare: if this one is taller than the one you remember, you remember this one instead. When you reach the end, the person you remember is the tallest of all.

A program does exactly that with a variable that holds the best so far. Two decisions make up the algorithm:

  1. Where to start. Before the loop, the best-so-far variable needs a starting value. The safest choice is the first value itself, since it is a real piece of data. Another choice is a value that every real value is guaranteed to beat: Integer.MAX_VALUE when looking for a minimum (every int is at most that), or Integer.MIN_VALUE when looking for a maximum.
  2. How to update. Inside the loop, compare the current value with the best so far. For a maximum, if (value > best); for a minimum, if (value < best). Only when the comparison is true, replace the best so far.

Key idea

To find a maximum or minimum, keep a “best so far” variable. Start it at the first value (or at a value every real value will beat), and inside the loop replace it whenever the current value is larger (for a maximum) or smaller (for a minimum).

Worked example: The highest score

HighestScore.java
import java.util.Scanner;

public class HighestScore
{
    public static void main(String[] args)
    {
        Scanner input = new Scanner("5 71 88 64 93 80");
        int players = input.nextInt();
        int highest = input.nextInt();
        for (int player = 2; player <= players; player++)
        {
            int score = input.nextInt();
            if (score > highest)
            {
                highest = score;
            }
        }
        System.out.print("Highest: ");
        System.out.println(highest);
    }
}

Line 9 reads the first score straight into highest. Because the first value has already been used, the loop on line 10 starts player at 2 and runs for the remaining four players.

player score score > highest? highest after the if
(line 9) 71 71
2 88 true 88
3 64 false 88
4 93 true 93
5 80 false 93
Highest: 93

If the loop had started player at 1, it would try to read six scores when only five remain, an off-by-one error. Starting at 2 matches the fact that one score was read before the loop.

Now vary three things: look for the minimum, start at Integer.MAX_VALUE instead of the first value, and also remember where the minimum happened. Recording the position is a small addition: whenever the best so far changes, store the day too.

Worked example: The coldest day and when it happened

ColdestDay.java
import java.util.Scanner;

public class ColdestDay
{
    public static void main(String[] args)
    {
        Scanner input = new Scanner("5 -3 4 -8 2 -5");
        int days = input.nextInt();
        int coldest = Integer.MAX_VALUE;
        int coldestDay = 0;
        for (int day = 1; day <= days; day++)
        {
            int temp = input.nextInt();
            if (temp < coldest)
            {
                coldest = temp;
                coldestDay = day;
            }
        }
        System.out.print("Coldest: ");
        System.out.print(coldest);
        System.out.print(" on day ");
        System.out.println(coldestDay);
    }
}
day temp temp < coldest? coldest, coldestDay
start Integer.MAX_VALUE, 0
1 -3 true -3, 1
2 4 false -3, 1
3 -8 true -8, 3
4 2 false -8, 3
5 -5 false -8, 3
Coldest: -8 on day 3

On day 1, -3 < 2147483647 is certainly true, so the first real temperature always replaces the starting value. That is why Integer.MAX_VALUE is safe for a minimum: no int is larger. This version reads every value inside the loop, so day starts at 1. Lines 16 and 17 are both inside the braces, so the day is recorded only when the temperature is a new low.

Watch out

Starting the best so far at 0. Zero feels like a natural starting point, the way it is for a sum, but here it can be wrong. Look at a cold week where every high temperature is below zero:

MaxStartZero.java
import java.util.Scanner;

public class MaxStartZero
{
    public static void main(String[] args)
    {
        Scanner input = new Scanner("4 -6 -2 -9 -4");
        int days = input.nextInt();
        int warmest = 0;
        for (int day = 1; day <= days; day++)
        {
            int temp = input.nextInt();
            if (temp > warmest)
            {
                warmest = temp;
            }
        }
        System.out.println(warmest);
    }
}

This prints 0, but no day had a high of 0. Every temperature (-6, -2, -9, -4) is less than 0, so temp > warmest is never true and the made-up starting value is never replaced. Starting at 0 works only if you know some value will beat it. The fix is to start with the first real value, as HighestScore.java does:

MaxStartFirst.java
import java.util.Scanner;

public class MaxStartFirst
{
    public static void main(String[] args)
    {
        Scanner input = new Scanner("4 -6 -2 -9 -4");
        int days = input.nextInt();
        int warmest = input.nextInt();
        for (int day = 2; day <= days; day++)
        {
            int temp = input.nextInt();
            if (temp > warmest)
            {
                warmest = temp;
            }
        }
        System.out.println(warmest);
    }
}

This prints -2, the warmest of the four.

Pause and try

Question 11 · Tracing

What does this program print?

MinUpdates.java
import java.util.Scanner;

public class MinUpdates
{
    public static void main(String[] args)
    {
        Scanner input = new Scanner("4 12 9 15 9");
        int count = input.nextInt();
        int lowest = input.nextInt();
        int updates = 0;
        for (int i = 2; i <= count; i++)
        {
            int value = input.nextInt();
            if (value < lowest)
            {
                lowest = value;
                updates++;
            }
        }
        System.out.print("Lowest: ");
        System.out.println(lowest);
        System.out.print("Updates: ");
        System.out.println(updates);
    }
}
Check your reasoning

It prints:

Lowest: 9
Updates: 1
i value value < lowest? lowest, updates
(line 9) 12 12, 0
2 9 true 9, 1
3 15 false 9, 1
4 9 false 9, 1

The second 9 does not count as an update, because 9 < 9 is false: a tie is not “smaller.” If you got Updates: 2, you treated < as if it were <=.

Reread 2.9.6 Finding the Minimum or Maximum if your answer differed.

Question 12 · Short answer

ColdestDay.java started coldest at Integer.MAX_VALUE. Would the program still work if it started coldest at 0 instead? Explain, using a week of summer temperatures such as 18, 25, and 21 as an example.

Check your reasoning

Model answer: No, not for every input. It happens to work for the given data because some temperatures are below 0. But in a week like 18, 25, and 21, every temperature is greater than 0, so temp < coldest is never true and the program reports 0, a temperature that never happened. Integer.MAX_VALUE works because every real temperature is less than or equal to it, so the first temperature always replaces it.

A complete answer says:

  • The starting value must be one that real data will replace (or a real data value itself).
  • With a start of 0, positive-only data never beats it, so the minimum comes out as 0.

Reread 2.9.6 Finding the Minimum or Maximum if your reasoning differed.

Wrap-up · 1 of 5

Putting it together

Real programs rarely use just one of these algorithms. They run several in the same loop, each with its own variable. This program reads a week of step counts from a fitness tracker and reports the total, the average, how many days met a 10,000-step goal, and the best day. Comments (Topic 1.8) label the job of each variable.

Worked example: A weekly step report

StepReport.java
import java.util.Scanner;

public class StepReport
{
    public static void main(String[] args)
    {
        Scanner input = new Scanner("7 8200 10450 6100 12000 9800 10450 6000");
        int days = input.nextInt();

        int total = 0;          // sum of all step counts
        int goalDays = 0;       // days with at least 10000 steps
        int best = 0;           // most steps in one day so far
        int bestDay = 0;        // the day that happened

        for (int day = 1; day <= days; day++)
        {
            int steps = input.nextInt();
            total += steps;
            if (steps >= 10000)
            {
                goalDays++;
            }
            if (day == 1 || steps > best)
            {
                best = steps;
                bestDay = day;
            }
        }

        System.out.print("Total: ");
        System.out.println(total);
        System.out.print("Average: ");
        System.out.println((double) total / days);
        System.out.print("Goal days: ");
        System.out.println(goalDays);
        System.out.print("Best: ");
        System.out.print(best);
        System.out.print(" on day ");
        System.out.println(bestDay);
    }
}

Four algorithms share one loop:

Algorithm Variable(s) Lines
Sum total 10, 18
Count with a test goalDays 11, 19–22
Maximum (and when) best, bestDay 12–13, 23–27
Average total and days 33, after loop

Line 23 is a new twist on the maximum. Instead of reading the first value before the loop, it says “replace the best if this is day 1 or the steps beat the best so far.” On day 1 the left side is true, so || short-circuits (Topic 2.5) and the first value always becomes the best. After that, day == 1 is false and only steps > best matters.

day steps total goalDays best, bestDay
1 8200 8200 0 8200, 1
2 10450 18650 1 10450, 2
3 6100 24750 1 10450, 2
4 12000 36750 2 12000, 4
5 9800 46550 2 12000, 4
6 10450 57000 3 12000, 4
7 6000 63000 3 12000, 4

After the loop, line 33 computes (double) 63000 / 7, which is 9000.0:

Total: 63000
Average: 9000.0
Goal days: 3
Best: 12000 on day 4

Day 5 (9800) is close to the goal but is not counted, because 9800 >= 10000 is false. Each variable did its one job on every pass, and none of them interfered with the others.

The algorithms also combine in less obvious ways. There is an old shortcut for checking whether a number is divisible by 9: add up its digits, and if that sum is divisible by 9, so is the number. This snippet uses the digit algorithm to build a sum, then two divisibility tests to compare the shortcut with the direct check.

Worked example: The divisible-by-9 shortcut

int number = 7848;
int remaining = number;
int digitSum = 0;
while (remaining > 0)
{
    digitSum += remaining % 10;
    remaining /= 10;
}
System.out.print("Digit sum: ");
System.out.println(digitSum);
if (digitSum % 9 == 0)
{
    System.out.println("Digit sum is a multiple of 9");
}
if (number % 9 == 0)
{
    System.out.println("Number is a multiple of 9");
}

The loop visits 8, 4, 8, 7, so digitSum is 8 + 4 + 8 + 7 = 27. Then 27 % 9 is 0, and 7848 % 9 is also 0 (7848 = 9 × 872), so both ifs run:

Digit sum: 27
Digit sum is a multiple of 9
Number is a multiple of 9

Change number to 7849 and the digit sum becomes 28. Both 28 % 9 and 7849 % 9 are 1, so neither message prints. The shortcut and the direct test agree, as they always do for 9. A program like this is an original algorithm: no single standard pattern solves it, but it is built entirely from the ones in this chapter.

Wrap-up · 2 of 5

Vocabulary

Term Definition Example
standard algorithm A well-known step-by-step solution to a common problem that programmers reuse and adapt Summing values in a loop
running total The sum of every value looked at so far total after pass 3
accumulator A variable that collects a result a little at a time as a loop runs total += price;
average The sum of the values divided by how many values there are (double) sum / count
sentinel value A special value that is not real data and signals the end of the input -1 after quiz scores
frequency The number of times a condition is true 3 hot days
counter An accumulator that adds one each time something happens hotCount++;
evenly divisible Divides with a remainder of zero 84 % 7 == 0
divisor A whole number that divides another evenly 4 is a divisor of 12
digit One of the single figures 0–9 that make up a written number; % 10 gives the last one 4072 % 10 is 2
maximum The largest value in a series 93 in 71, 88, 64, 93, 80
minimum The smallest value in a series -8 in -3, 4, -8, 2, -5
best so far The variable in a minimum or maximum algorithm holding the smallest or largest value seen so far highest in HighestScore
Wrap-up · 3 of 5

Chapter summary

  • A sum uses an accumulator that starts at 0 before the loop, gains one value per pass with +=, and is used after the loop. Resetting it inside the loop throws away the running total.
  • An average is the sum divided by the count. Write (double) sum / count so the division keeps its decimal part, and check that the count is greater than zero first. A sentinel value lets a while loop read an unknown number of values.
  • Counting how often a condition is met puts count++ inside an if inside the loop. The condition, including its boundary (> versus >=), decides what is counted.
  • a % b == 0 tests whether a is evenly divisible by b; n % 2 == 0 tests for an even number. Inside a loop, it can find every divisor of a number.
  • % 10 gives the last digit of a nonnegative integer and / 10 removes it; a while (number > 0) loop repeating both visits every digit from right to left.
  • A minimum or maximum keeps a best-so-far variable that starts at the first value (or a value every real value will beat) and is replaced whenever the current value is smaller or larger.
Wrap-up · 4 of 5

Review questions

Question 13 · Multiple choice

What does this code print?

int sum = 0;
int count = 0;
for (int k = 1; k <= 10; k++)
{
    if (k % 3 == 0)
    {
        sum += k;
    }
    else
    {
        count++;
    }
}
System.out.println(sum);
System.out.println(count);
  1. 18 and then 7
  2. 18 and then 10
  3. 55 and then 7
  4. 18 and then 3
Check your reasoning

A. The loop runs for k from 1 to 10. When k is divisible by 3 (that is, 3, 6, and 9), the if adds k to sum, giving 3 + 6 + 9 = 18. On every other pass, the else adds one to count. There are 10 passes and 3 of them went to the if, so count is 7.

  • B is wrong: it counts every pass, but the else runs only when the if does not.
  • C is wrong: 55 is the sum of all of 1 to 10. Only the multiples of 3 are added.
  • D is wrong: 3 is how many numbers went to the if; count is changed only in the else.

Reread 2.9.3 Counting Values That Meet a Condition and 2.9.4 Testing Whether One Integer Divides Another if you chose differently.

Question 14 · Debugging

This code is supposed to count the numbers from 1 to 50 that are divisible by both 2 and 3. The correct answer is 8 (6, 12, 18, 24, 30, 36, 42, 48), but it prints 33. Find the error and correct it.

int count = 0;
for (int n = 1; n <= 50; n++)
{
    if (n % 2 == 0 || n % 3 == 0)
    {
        count++;
    }
}
System.out.println(count);
Check your reasoning

Line 4 uses || where it needs &&:

if (n % 2 == 0 && n % 3 == 0)

With ||, a number is counted when it is divisible by 2 or by 3, which matches 33 of the numbers from 1 to 50 (25 even numbers, plus the 8 odd multiples of 3: 3, 9, 15, …, 45). “Both” means both tests must be true, which is &&. With the fix, only the multiples of 6 pass, and the program prints 8. The loop and the counter were already correct; only the condition was wrong, which is why the condition is the first place to look when a count is too high or too low.

Reread 2.9.4 Testing Whether One Integer Divides Another if your answer differed.

Question 15 · Tracing

What does this code print? Trace number and zeros.

int number = 70300;
int zeros = 0;
while (number > 0)
{
    if (number % 10 == 0)
    {
        zeros++;
    }
    number /= 10;
}
System.out.print("Zeros: ");
System.out.println(zeros);
Check your reasoning

It prints Zeros: 3.

number at start number % 10 zeros
70300 0 1
7030 0 2
703 3 2
70 0 3
7 7 3

After the last pass, number is 0 and the loop ends. This combines the digit loop with the counting pattern: each digit is tested with an if, and only zeros are counted. The zeros at the right end are found too; each one is the last digit at some point before /= 10 removes it.

Reread 2.9.5 Pulling Apart the Digits of an Integer if your answer differed.

Question 16 · Multiple choice

A store’s daily sales are read by this program. Sales of 55 happened on both day 2 and day 4. What does it print?

TieLastDay.java
import java.util.Scanner;

public class TieLastDay
{
    public static void main(String[] args)
    {
        Scanner input = new Scanner("5 40 55 30 55 20");
        int days = input.nextInt();
        int best = input.nextInt();
        int bestDay = 1;
        for (int day = 2; day <= days; day++)
        {
            int sales = input.nextInt();
            if (sales >= best)
            {
                best = sales;
                bestDay = day;
            }
        }
        System.out.print("Best day: ");
        System.out.println(bestDay);
    }
}
  1. Best day: 2
  2. Best day: 4
  3. Best day: 55
  4. Best day: 5
Check your reasoning

B. The comparison on line 14 is >=, so a value that ties the best so far also replaces it.

day sales sales >= best? best, bestDay
(line 9) 40 40, 1
2 55 true 55, 2
3 30 false 55, 2
4 55 true (tie) 55, 4
5 20 false 55, 4
  • A is wrong: day 2 is what the program would print with >, which keeps the first of tied values. With >=, the last tie wins.
  • C is wrong: 55 is the best sales amount, stored in best; the program prints bestDay.
  • D is wrong: day 5 has the lowest sales, and 20 >= 55 is false.

Reread 2.9.6 Finding the Minimum or Maximum if you chose differently.

Question 17 · Short answer

A program reads quiz scores until it reaches a sentinel, then prints their average. A student suggests using 0 as the sentinel instead of -1. Explain why that is a bad choice, and say what makes a good sentinel.

Check your reasoning

Model answer: 0 is a real quiz score: a student who missed every question gets a 0. If 0 were the sentinel, the loop would stop at the first real 0 score, leaving it and every score after it out of both the sum and the count, so the average would be wrong. A good sentinel is a value that can never be real data, so reading it can only mean “stop.” Scores are never negative, so -1 can never be mistaken for a score.

A complete answer says:

  • 0 can be real data, so a real score would end the input early.
  • The scores after it (and the 0 itself) would be missing from the sum and count.
  • A sentinel must be a value outside the range of possible real values.

Reread 2.9.2 Computing an Average if your reasoning differed.

Question 18 · Tracing

What three lines does this code print? (Starting largest at 0 is safe here: why?)

int number = 2468;
int sum = 0;
int largest = 0;
while (number > 0)
{
    int digit = number % 10;
    sum += digit;
    if (digit > largest)
    {
        largest = digit;
    }
    number /= 10;
}
System.out.println(sum);
System.out.println(largest);
System.out.println(sum % largest == 0);
Check your reasoning

It prints:

20
8
false
number at start digit sum largest
2468 8 8 8
246 6 14 8
24 4 18 8
2 2 20 8

The loop runs a sum and a maximum together over the digits. The last line prints the value of the Boolean expression sum % largest == 0: 20 % 8 is 4, not 0, so it is false (20 is not divisible by 8).

Starting largest at 0 is safe because a digit is never less than 0, so the first digit is always at least as big as the start, and any positive digit replaces it. This is different from the cold-week temperatures in 2.9.6, where every real value was below 0. (The program assumes number is positive, so at least one digit is visited.)

Reread 2.9.5 Pulling Apart the Digits of an Integer and 2.9.6 Finding the Minimum or Maximum if your answer differed.

Wrap-up · 5 of 5

Reflection

  • I can trace a sum with an accumulator and explain why it starts at 0 before the loop. Reread
  • I can compute an average without losing the decimal part, and explain what a sentinel value is for. Reread
  • I can trace a loop that counts how many values meet a condition, including at the boundary. Reread
  • I can use % to test whether one integer is evenly divisible by another. Reread
  • I can use % 10 and / 10 in a loop to visit every digit of an integer. Reread
  • I can find a minimum or maximum and explain how the starting value can change the answer. Reread
  • I can trace a program that runs several of these algorithms in the same loop. Reread