Repeating an Action: [1..n] vs. [0..∞)

[1..n] Iterations

Accumulation and You

Mathemeticians have short-hand notation for accumulating a sequence of values as either a sum:

      ∞
    -----
    \
     >   f(x ) = f(x ) + f(x ) + f(x ) + . . .
    /       i       0       1       2
    -----
    i = 0

Or a product:

      ∞
    -----
     | |
     | | f(x ) = f(x ) * f(x ) * f(x ) * . . .
     | |    i       0       1       2
     | |
    i = 0

Both of these can be placed in a C++ program by using a simple counting loop plus a little help. First the counting loop:

    count = 0;
    while (count != limit)
    {
        count = count + 1;
    }

Note how I've replaced the ∞ with a specific upper limit here. Also note that the upper limit is a strict bound, that is, our counter will be using the values [0..limit). The loop will end as soon as the counter reaches limit.

Special tasks call for special values — identities.

Next we need a little help. In general, what we need is called an accumulator variable. For the summation, we'll need a variable to track our running total. I'll call this helper variable sum and initialize it to 0. (0 is chosen here because that is the identity for addition.) Then, as the loop progresses, I'll simply add each next value onto the accumulator variable to represent a running total:

    sum = 0;
    count = 0;
    while (count != limit)
    {
        sum = sum + /* new term */;
        count = count + 1;
    }

Two things tend to confuse folks here: the whole idea of a 'running total' and the /* new term */ bit there. First things first, what's a 'running total'? Well, look at this addition problem:

    13 + 4 + 2 + 9

You and I would try to mentally group things into nice/useful packages based on our knowledge of the rules of addition. Maybe we'd see that 13+2 would give 15, leaving the 4+9 to make 13, which all together gives us 28. Or maybe we'd notice the 4+9 makes another 13 first and then toss in that 2*13 makes 26 and then tack on the 2 to make the final 28. However we'd do it, it is most distinctly NOT the computer's approach.

The computer approaches everything from a very simplistic point of view, recall. It sees the sum like this:

    (((13 + 4) + 2) + 9)

I know, I know...it looks more complicated... But remember what the parentheses are doing. They are breaking the expression up into smaller groups — pairs in fact:

    ( ( (13 + 4) + 2 ) + 9 )
    \ | \______/     |     /
    |  \____________/      |
     \____________________/

The inside pair is done first giving us 17 to carry on to be the 'left-hand addend' of the second pair: 17+2. This, of course, gives us 19. And this moves on to become the 'left-hand addend' for the third pair: 19+9. And finally we arrive at the same answer as before: 28. We simply took an entirely different route to get here.

But how does all of this lead us to a 'running total'? Well, we can take any sequence of values to be added together and, without changing the result, prepend an identity element to the sequence. For instance, the above sum would remain 28 even if we placed a 0 up front:

    0 + 13 + 4 + 2 + 9

Right? And, the computer sees it as, then:

    ((((0 + 13) + 4) + 2) + 9)

A set of four pairs to be added. Also note that the pairs are nested such that the first or inner-most pair forms the left-hand member of the second pair. We could represent this sequence of events in a more mundane fashion like so:

       0
    + 13
    ----
      13
    +  4
    ----
      17
    +  2
    ----
      19
    +  9
    ----
      28

By simply adding a little labling, we see what's going on and how it all makes up a 'running total':

       0     <-- initialize scratch pad
    + 13     <-- first value/term
    ----
      13     <-- partial sum
    +  4     <-- second value/term
    ----
      17     <-- partial sum
    +  2     <-- third value/term
    ----
      19     <-- partial sum
    +  9     <-- fourth value/term
    ----
      28     <-- total sum

So, in case that didn't already answer it (I can see some of you are losing that look of utter confusion already), what's that /* next term */ thingy? It represents the next value to be added onto the current/partial sum/total. How we actually arrive at these values is application dependent, but most often for us, we'll be reading them in from the user:

    sum = 0;
    count = 0;
    while (count != limit)
    {
        cin >> term;
        sum = sum + term;
        count = count + 1;
    }

The accumulation of a product is similar, except we'd be multiplying the 'factors' together and we'd therefore want to initialize the product to 1:

    product = 1;
    count = 0;
    while (count != limit)
    {
        cin >> factor;
        product = product * factor;
        count = count + 1;
    }

And, something math didn't necessarily show you (yet) is a non-numeric accumulator:

    line = "";
    count = 0;
    while (count != limit)
    {
        cin >> word;
        line = line + word + ' ';
        count = count + 1;
    }

Note the small adjustment to not concatenate the words directly to one-another. We don't typically need to know what kind or how much spacing the >> operation threw out — we just need to separate by at least a single space what they obviously had separated during entry.

Of course, we don't normally ask the user to enter a certain limited number of words in a line...we'd most likely let them enter their words and just keep going until they'd ended their line...maybe we can go back to an 'infinite' loop here:

    line = "";
    while (cin.peek() != '\n' && isspace(cin.peek()))
    {
        cin.ignore();
    }
    while (cin.peek() != '\n')
    {
        cin >> word;
        line = line + word + ' ';
        while (cin.peek() != '\n' && isspace(cin.peek()))
        {
            cin.ignore();
        }
    }

Now, if not the sky, then the new-line's the limit!

(I'm so sorry...that just slipped out...*shakes head* *snicker*)

But it does raise a valid point — this code expects all of the input to be on a single line. If you have [possibly] multiple lines of input coming in, you'll have to alter this loop a little...

Priming loops...

Isn't our update lovely, though? And the initialization... Hey! They're the same! The fact that they are also both while loops in their own right just makes it ickier...the compiler should have no trouble following it.

But isn't this just a glorified getline? Well, kind-of. getline would respect internal spacing whereas we specifically throw it all away and compress it to a single space. Both of these input styles have their place. I leave it to you and your application to decide which is useful where.


And, as some of you may have guessed, we don't have to limit the user on the numeric problems, either. If we think about it a bit, we can simply have them enter some non-numeric value when they are done with their list:

SummationMultiplication
    sum = 0;
    cin >> term;
    while (!cin.fail())
    {
        sum = sum + term;
        cin >> term;
    }
    product = 1;
    cin >> factor;
    while (!cin.fail())
    {
        product = product * factor;
        cin >> factor;
    }

(Note how the initialization and update have changed to, again, be identical.)

And then we just need to clean up after they are done:

    cin.clear();
    cin.ignore(numeric_limits<streamsize>::max(), '\n');

The only limitation they'll have is that of the storage capacity of our accumulator's data type.

[MORE SOON..?]

[0..∞)

The Classic Yes/No Loop
    cout << "\nWould you like to use the program?  ";
    cin >> yes_no;
    cin.ignore(numeric_limits<streamsize>::max(), '\n');
    while ( toupper(yes_no) == 'Y' )
    {
        // do your thing here...
        cout << "\nWould you like do it again?  ";
        cin >> yes_no;
        cin.ignore(numeric_limits<streamsize>::max(), '\n');
    }

Note that the sense of the leading question and the follow-up question should be the same. If one asks a positive question and the other a negative question, you won't be able to code the test/condition properly for the loop!

A Menu Loop
    char choice;
    bool done;

    done = false;
    while ( !done )
    {
        cout << " . . . ( menu options here and prompt ) . . . ";
        cin >> choice;
        cin.ignore(numeric_limits<streamsize>::max(), '\n');
        choice = toupper(choice);

        if ( choice == '1' || choice == '??' )
        {
            // code block for first option
        }
        else if ( choice == '2' || choice == '??' )
        {
            // code block for second option
        }
        else if ( choice == '...' || choice == '...' )
        {
            // else-if clauses for other options
        }
        else if ( choice == '??' || choice == 'Q' || choice == 'X' )
        {
            // code block for quitting/exiting option
            done = true;
        }
        else
        {
            cout << " . . . ( invalidity message ) . . . ";
        }
    }

Forcing the nature of a thing...

Truly, we've forced the while loop to do something here that it isn't naturally going to want to do. As with the validation loop and the flagged input loop, whiles tend to want to execute zero (0) or more times. Here, by setting the done variable to an initial state of false, we've forced the loop to execute its body statements at least once. Later we'll learn that there is another loop that is perfect for this situation! (*ahem* do loop! *cough*) But for now, I'll bear the bad karma for your transgressions in [relative] silence.

It is recommended that you have 9 or fewer options in your menu to simplify their entry and processing. (If you want more, you can use sub-menus — just have another menu structure as above nested inside one of the choice branches!) (If you just want 10, you can number them '0' thru '9'. But people outside CompSci and/or Math will probably be slightly confused.)

Be sure to change the '??' parts to the appropriate characters for your particular menu. Oh! And don't forget to actually change the literal strings to ones suitable for your application! (*grin*)

If you'd like to add a final plea for life to your quitting block, it would probably then look something like this:

  cout << "\n\aAre you sure you ~really~ want to quit?!  ";
  cin >> yes_no;
  cin.ignore(numeric_limits<streamsize>::max(), '\n');
  done = toupper(yes_no) == 'Y';
 

[MORE SOON..?]

bool as a Memory Device

To bool or to !bool, that is the question!

[COMING SOON!]

Locating Something Inside a string

Whither, thither, yon...um...'Not Found'.

[COMING SOON!]

replace'ing Some of a string's Contents

When the substitution text contains [part of] the substituted for text...

[COMING SOON!]

Repeated Alternation

Clever use of basic numeric properties and arithmetic.

[COMING SOON!]