Skip to main content

Section 8.7 Tables

One of the things loops are good for is generating tabular data. For example, before computers were readily available, people had to calculate logarithms, sines and cosines, and other common mathematical functions by hand. To make that easier, there were books containing long tables where you could find the values of various functions. Creating these tables was slow and boring, and the result tended to be full of errors.
When computers appeared on the scene, one of the initial reactions was, β€œThis is great! We can use the computers to generate the tables, so there will be no errors.” That turned out to be true (mostly), but shortsighted. Soon thereafter computers and calculators were so pervasive that the tables became obsolete.
Well, almost. It turns out that for some operations, computers use tables of values to get an approximate answer, and then perform computations to improve the approximation. In some cases, there have been errors in the underlying tables, most famously in the table the original Intel Pentium used to perform floating-point division.
Although a β€œlog table” is not as useful as it once was, it still makes a good example of iteration.
Listing 8.7.1. This active code outputs a sequence of values in the left column and their base 2 logarithms in the right column.
The sequence \t represents a tab character. A tab character causes the cursor to shift to the right until it reaches one of the tab stops, which are normally every eight characters. This helps the second column stay lined up even when the length of the number in the first column goes from 1 to 2 digits. If we used the string " " to space out the columns, the second column would jump over when the first column changed length. We will learn about more sophisticated ways to space out data as it is printed later, but for now, tabs do a good enough job.
When making a table, or doing any work with a loop, it is important to think about what variable really is the loop control variable. Say you are asked to print a table of investment income like the one below. The investment starts at $10,000 and grows by 20% until it reaches at least $100,000:
Year	Investment Amount
------------------------
1	$10000
2	$12000
3	$14400
4	$17280
5	$20736
6	$24883.2
7	$29859.8
8	$35831.8
9	$42998.2
10	$51597.8
11	$61917.4
12	$74300.8
13	$89161
14	$106993
Stop and think about what is really controlling that loop? Does the problem specify how many months the process takes? No - it says that we want to stop when we hit $100,000+ not after X months. (Though you could do math to figure out the number of months.) So despite counting from 1 to 14, this isn’t really a counting loop. It is a sentinel value loop that is looking for the balance to become $100,000+. Here is what the program might look like:
Listing 8.7.2.
Key things to note:
  • balance is the loop control variable. It is serving as an accumulator to store the interest earned each year.
  • years is a counter variable we increase by one each time through the loop, but the loop logic does not depend on its value.
  • There are multiple updates that need to happen each year. We need to increment years, calculate the interest based on the current balance, and then update the balance.
  • The loop does not print the last row of the table. After the updates are done, if we have hit the TARGET, the loop stops without printing the final value. So we do one last print statement after the loop to handle that row.
  • Instead of magic numbers for START_VALUE, GROWTH_RATE,and TARGET, we have constants. When values in a program should be reconfigurable, but do not come from input, it is a good idea to make them constants and declare them together in one place.

Insight 8.7.1.

It is often necessary (or at least easier) to handle the first or last item in a sequence before or after the loop that handles the other items.
Doing this is better than putting an if inside the loop to do something special only in the first or last iteration. We could move the final output inside the loop above by doing:
Listing 8.7.3.
    ...
    balance += interest;
    if (balance >= TARGET) {
        cout << years << "\t$" << balance << endl;
    }
}
That solution needless complicates every iteration of the loop to guard against the special case that we are actually now finished.

Checkpoint 8.7.1.

Let’s write the code that prints out the powers of two up to 16.

Checkpoint 8.7.2.

Checkpoint 8.7.3.

The code below prints out the first 10 numbers and their squares. How can we modify it to print out a table of just the first five odd numbers (1, 3, 5, 7, 9) and their squares?
int main() {
  int x = 1;
  while (x < 11) {
    cout << x << "\t" << pow(x, 2) << endl;
    x = x + 1;
  }
}
  • Change x < 11 to x < 6.
  • That would count 1 to 5 including even numbers.
  • Change x = x + 1 to x = x + 2.
  • That will count by 2s, giving us the first five odd numbers.
  • Change x < 11 to x < 6 and change x = x + 1 to x = x + 2.
  • That will count by 2s but stop at 5. We will only get 1, 3, 5.
You have attempted of activities on this page.