Section 4 - A Closer Look at While Loops
Let's dig a little deeper into the second type of loop, the while loop.
4A.4.1 While Loops - A Closer Look
The only portion of the loop control is the test, and this is done at the beginning of every pass, including the first. Since we have already seen a simple while loop, let's look at one that is a little more interesting.
Suppose you borrowed $500,000 to buy a home five years ago. You were given a 6% fixed rate loan for 30 years. If you do the math, or ask the bank, you will find that your monthly payment is $2998. (This can vary depending on how often the interest "compounds," but the payment will be very close to this number, regardless.) You make your payments and five years pass. You look at your statement and see that the remaining principal on your loan is $465,254, which means that after five years, you still owe a lot of money!
There are still 25 years to go on your loan -- that's 300 monthly payments remaining. One day while you are writing the monthly mortgage check, you notice that you could pay an additional $250 without feeling the pain, and you get to thinking, "If I did this every month, how much would I save over the life of the loan?" Even more interesting, "How much sooner would I pay off the loan?" Being a computer programmer, you know it would only take you half an hour to write the program to solve this little problem, and best of all, you get to use your favorite loop: the while loop.
The reason that this might naturally lend itself to a while loop, as opposed to a for loop, is that you don't really know how many times the loop will cycle. If you did, you would have your answer. After all, you are trying to figure out how many payments you need to make to get the balance down to $0. How do you think about the problem?
Well, we start the principal off at the current amount, $465,254. Each month you have to do two things. First, you have to add the interest that the bank (or more likely the hedge-fund that owns the securitization into which your loan has been swallowed!) accrues each month. This is easy. You take the monthly interest, 6% / 12 or .5%, and multiply the principal by 1.005. This makes the principal a little bit larger at the end of the month and that's exactly how mortgages work. Next you subtract your monthly payment, which is $2998 + $250, that is, your original monthly payment, plus the $250 you are thinking about adding each month. That is, you subtract $3248.
You do this in a loop, over and over. Each loop pass you multiply the remaining principal by 1.005, and then you subtract $3248.
How long do you do it? That's what you want to know! You can't say "do it for 270 months" or "do it for 194 months" because the very thing you are trying to discover is how many months it takes to get the balance to 0. Instead, you do it as long as "the principal is greater than zero."
One of the things you'll need to do, along the way, is show how many months have passed. You can keep track of that using a numMonths variable that starts at 0 and increases by 1 each loop pass. Another thing you'll have to do when you are done is figure out how much money you have saved. Once you have calculated numMonths, this will be easy.
I'm going to give you a chance to figure this one out on your own before you see my solution. An important thing to keep in mind is the following: You may want to change the interest rate or the amount extra you pay each month, so it is best to not put constants like 6% or 2998 directly into your calculations, but instead, make these values symbolic variables at the top of the program. That way, you can rerun the program with your own, personal figures and find out how much you can save under different scenarios.
For the fun of it, and to make the output a little more interesting, I decided to print out the principal at the end of each year, i.e., every 12 months. You should try to do that, as well, when you write your program. Here's mine (don't look until you've got yours ready!):
#include <iostream> using namespace std; int main() { float moRate, yrRate, origPayment, payment, principal, amountSaved, extraAmount; int numMonths, monthsSaved; // annual amounts assuming $500k for 30 years, but after 5 years principal = 465254; // remaining principal at the moment yrRate = .06; // 6% origPayment = 2998; // fixed monthly pmt bank ordered you to pay extraAmount = 250; // convert % to monthly values: moRate = yrRate/12; payment = origPayment + extraAmount; numMonths = 0; while (principal > 0) { // start by adding interest charge to principal: principal *= (1 + moRate); // now make payment principal -= payment; numMonths++; // every 12 months we'll print out a balance if (numMonths%12 == 0) cout << "Balance after "<< numMonths << " months = $" << principal << endl; } cout << "You paid off the loan in " << numMonths << " months." << endl; monthsSaved = 300 - numMonths; // 25 years less the actual time amountSaved = 300 * origPayment - numMonths * payment; cout << "You paid it off " << monthsSaved << " months early.\n"; cout << "You saved $" << amountSaved << endl; return 0; } /* -------------------- RUN -------------------------- Balance after 12 months = $453884 Balance after 24 months = $441813 Balance after 36 months = $428997 Balance after 48 months = $415390 Balance after 60 months = $400945 Balance after 72 months = $385608 Balance after 84 months = $369326 Balance after 96 months = $352039 Balance after 108 months = $333686 Balance after 120 months = $314201 Balance after 132 months = $293515 Balance after 144 months = $271552 Balance after 156 months = $248235 Balance after 168 months = $223480 Balance after 180 months = $197197 Balance after 192 months = $169294 Balance after 204 months = $139670 Balance after 216 months = $108219 Balance after 228 months = $74827.5 Balance after 240 months = $39376.8 Balance after 252 months = $1739.57 You paid off the loan in 253 months. You paid it off 47 months early. You saved $77656 Press any key to continue . . . --------------------------------------------------- */
There are some things to note about this example.
- You could have used a for loop. There is an initialization and iteration (can you find that?) that can be neatly folded into a loop control. This is an example of a "toss-up." Some programmers would use a for, others would use a while.
- Check out the way in which I used the % operator to print partial balances only in the whole years rather than every month.
- There are other ways to do this. For one thing, you can come up with a single formula if you are a mathematical type. However, this example demonstrates that even if you aren't too good at math, you can devise this simple solution.
- You might say, "Yeah - but who's got an extra $250 each month?" You might be surprised. Some people buy lunch six days a week at about $10 a day, when they could eat a home-packed lunch that costs $2 on average. That's $192 right there. Maybe you have a gourmet coffee every day costing $4. There is $120 you could recapture. Do you get HBO? Do you need HBO? What big purchases you put off for a few months or years when you can do the purchase and pay the extra $250? These are just thoughts.
- Of course there are some tax issues, but, even if you are in the highest 50% (+/-) fed + state bracket for all 25 years, you would still save almost $40,000 after taxes. Also, even if you sell the house in five years, if you use the same strategy on your next home, then it is just as good -- if not better. The figures on the two homes, combined, will add up to savings that meet or beat the ones above.
4A.4.2 Do While Loops
The body of the while loop may not get executed even once, due to the test being false right off the bat. That's often desired, but not always. Here (again for some of you) is a little input filter that uses the ordinary while loop:
double withdrawal; // get the withdrawal amount from user cout << "Amount of withdrawal ($20 minimum): "; cin >> withdrawal; // trap user until they follow directions while (withdrawal < 20) { cout << "$20 Minimum. \nPlease try again: "; cin >> withdrawal; } /* ------------------- Amount of withdrawal ($20 minimum): 18 $20 Minimum. Please try again: 25 New balance:975.03 ... etc. ------------------- */
The problem, above, is that we have the same input statement duplicated, and it's always bad to duplicate code if we can help it. We avoid having two separate input statements by using a variation that performs the test at the end of the loop: the do/while statement:
cout << "Amount of withdrawal? "; // filter input until at least $20 do { cout << "($20 Minimum....) "; cin >> withdrawal; } while (withdrawal < 20); /* --------------------------- Amount of withdrawal?($20 Minimum) ... 4 ($20 Minimum) ... 0 ($20 Minimum) ... 11 ($20 Minimum) ... 23 New balance:957.0 ... etc. ----------------------- */
As with the for loop, the body is a single statement. If you only have one statement to do, you don't need the braces. If you have more, you need them.
Always indent the body of a for, do-while or while loop.