Looping


Looping is when statements are executed repeatedly. This technique can come in very handy, because it means that you can repeat operations as many times as you want (thousands, even millions, of times) without having to write the same code each time.

As a simple example, consider the following code for calculating the amount of money in a bank account after 10 years, assuming that interest is paid each year and no other money flows into or out of the account:

 double balance = 1000; double interestRate = 1.05; // 5% interest/year balance *= interestRate; balance *= interestRate; balance *= interestRate; balance *= interestRate; balance *= interestRate; balance *= interestRate; balance *= interestRate; balance *= interestRate; balance *= interestRate; balance *= interestRate; 

Writing the same code out 10 times seems a bit wasteful, and what if you wanted to change the duration from 10 years to some other value? You'd have to manually copy the line of code the required amount of times, which would be a bit of a pain!

Luckily, you don't have to do this. Instead, you can just have a loop that executes the instruction you want the required number of times.

Another important type of loop is one where you loop until a certain condition is fulfilled. These loops are slightly simpler than the situation detailed above (although no less useful), so they're a good starting point.

do Loops

do loops operate in the following way. The code you have marked out for looping is executed, then a Boolean test is performed, and the code executes again if this test evaluates to true, and so on. When the test evaluates to false the loop exits.

The structure of a do loop is as follows:

 do {    <code to be looped> } while (<Test>); 

where <Test> evaluates to a Boolean value.

Note

The semicolon after the while statement is required, and it's a common error to leave this out.

For example, you could use this to write out the numbers from 1 to 10 in a column:

 int i = 1; do { Console.WriteLine("{0}", i++); } while (i <= 10); 

Here, you use the suffix version of the ++ operator to increment the value of i after it is written to the screen, so you need to check for i<=10 in order to include 10 in the numbers written to the console.

The following Try It Out uses this for a slightly modified version of the code in the introduction to this section, where you calculated the balance in an account after 10 years. Here, you will use a loop to calculate how many years it will take to get a specified amount of money in your account based on a starting amount and an interest rate.

Try It Out – Using do Loops

image from book
  1. Create a new console application called Ch04Ex04 in the directory C:\BegVCSharp\Chapter4.

  2. Add the following code to Program.cs:

    static void Main(string[] args) { double balance, interestRate, targetBalance; Console.WriteLine("What is your current balance?"); balance = Convert.ToDouble(Console.ReadLine()); Console.WriteLine("What is your current annual interest rate (in %)?"); interestRate = 1 + Convert.ToDouble(Console.ReadLine()) / 100.0; Console.WriteLine("What balance would you like to have?"); targetBalance = Convert.ToDouble(Console.ReadLine()); int totalYears = 0; do { balance *= interestRate; ++totalYears; } while (balance < targetBalance); Console.WriteLine("In {0} year{1} you'll totalYears, totalYears == 1 ? "" : "s", balance); Console.ReadKey(); } 

  3. Execute the code and enter some values. The result is shown in Figure 4-4.

    image from book
    Figure 4-4

How It Works

This code simply repeats the simple annual calculation of balance with a fixed interest rate as many times as is necessary for the balance to satisfy the terminating condition. You keep a count of how many years have been accounted for by incrementing a counter variable with each loop cycle:

int totalYears = 0; do {    balance *= interestRate;    ++totalYears; } while (balance < targetBalance);

You can then use this counter variable as part of the result output:

Console.WriteLine("In {0} year{1} you'll have a balance of {2}.",                   totalYears, totalYears == 1 ? "" : "s", balance);

Note

Note that this is perhaps the most common usage of the ?: (ternary) operator — to conditionally format text with the minimum of code. Here, you output an "s" after "year" if totalYears isn't equal to 1.

Unfortunately, this code isn't perfect. Consider the situation in which the target balance is less than the current balance. The output will be along the lines of that shown in Figure 4-5.

image from book
Figure 4-5

do loops always execute at least once. Sometimes, as in this situation, this isn't ideal. Of course, you could add an if statement:

int totalYears = 0; if (balance < targetBalance) {    do    {       balance *= interestRate;       ++totalYears;    }    while (balance < targetBalance); } Console.WriteLine("In {0} year{1} you'll have a balance of {2}.",                   totalYears, totalYears == 1 ? "" : "s", balance);

But this does seem as if you're adding unnecessary complexity. A far better solution is to use a while loop.

image from book

while Loops

while loops are very similar to do loops, but have one important difference. The Boolean test in a while loop takes place at the start of the loop cycle, not the end. If the test evaluates to false, then the loop cycle is never executed. Instead, program execution jumps straight to the code following the loop.

while loops are specified in the following way:

 while (<Test>) {    <code to be looped> } 

and can be used in almost the same way as do loops, for example:

int i = 1; while (i <= 10) {    Console.WriteLine("{0}", i++); }

This code gives the same result as the do loop you saw earlier; it outputs the numbers 1 to 10 in a column.

The following Try It Out demonstrates how you can modify the last example to use a while loop.

Try It Out – Using while Loops

image from book
  1. Create a new console application called Ch04Ex05 in the directory C:\BegVCSharp\Chapter4.

  2. Modify the code as follows (use the code from Ch04Ex04 as a starting point, and remember to delete the while statement at the end of the original do loop):

    static void Main(string[] args) {    double balance, interestRate, targetBalance;    Console.WriteLine("What is your current balance?");    balance = Convert.ToDouble(Console.ReadLine());    Console.WriteLine("What is your current annual interest rate (in %)?");    interestRate = 1 + Convert.ToDouble(Console.ReadLine()) / 100.0;    Console.WriteLine("What balance would you like to have?");    targetBalance = Convert.ToDouble(Console.ReadLine());        int totalYears = 0; while (balance < targetBalance)    {       balance *= interestRate;       ++totalYears;    }    Console.WriteLine("In {0} year{1} you'll have a balance of {2}.",                      totalYears, totalYears == 1 ? "" : "s", balance);    Console.ReadKey(); }

  3. Execute the code again, but this time use a target balance that is less than the starting balance, as shown in Figure 4-6.

    image from book
    Figure 4-6

How It Works

This simple change from a do loop to a while loop has solved the problem in the last example. By moving the Boolean test to the start you provide for the circumstance where no looping is required, and you can jump straight to the result.

There are, of course, other alternatives in this situation. For example, you could check the user input to ensure that the target balance is greater than the starting balance. In situations like this, you can place the user input section in a loop as follows:

Console.WriteLine("What balance would you like to have?"); do {    targetBalance = Convert.ToDouble(Console.ReadLine()); if (targetBalance <= balance) Console.WriteLine("You must enter an amount greater than " + "your current balance!\nPlease enter another value.");  } while (targetBalance <= balance); 

This will reject values that don't make sense, so you get output as shown in Figure 4-7.

image from book
Figure 4-7

This validation of user input is an important topic when it comes to application design, and you see many examples of it over the course of this book.

image from book

for Loops

The last type of loop you look at in this chapter is the for loop. This type of loop is one that executes a set number of times and maintains its own counter. To define a for loop you need the following information:

  • A starting value to initialize the counter variable

  • A condition for continuing the loop, involving the counter variable

  • An operation to perform on the counter variable at the end of each loop cycle

For example, if you want a loop with a counter that increments from 1 to 10 in steps of one, then the starting value is 1, the condition is that the counter is less than or equal to 10, and the operation to perform at the end of each cycle is to add one to the counter.

This information must be placed into the structure of a for loop as follows:

 for (<initialization>; <condition>; <operation>) {    <code to loop> } 

This works in exactly the same way as the following while loop:

 <initialization> while (<condition>) {    <code to loop>    <operation> } 

But the format of the for loop makes the code easier to read, because the syntax involves the complete specification of the loop in one place, rather than divide it over several statements in different areas of the code.

Earlier, you used do and while loops to write out the numbers from 1 to 10. The code that follows shows what is required for you to do this using a for loop:

 int i; for (i = 1; i <= 10; ++i) { Console.WriteLine("{0}", i); } 

The counter variable, an integer called i, starts with a value of 1 and is incremented by 1 at the end of each cycle. During each cycle the value of i is written to the console.

Note that when code resumes after the loop i has a value of 11. This is because at the end of the cycle where i is equal to 10, i is incremented to 11. This happens before the condition that i<= 10 is processed, at which point the loop ends.

As with while loops, for loops only execute if the condition evaluates to true before the first cycle, so the code in the loop doesn't necessarily run at all.

As a final note, you can declare the counter variable as part of the for statement, rewriting the preceding code as:

 for (int i = 1; i <= 10; ++i) { Console.WriteLine("{0}", i); }

If you do this, though, the variable i won't be accessible from code outside this loop (see the section on variable scope in Chapter 6).

The next Try It Out uses for loops. Since you have used loops quite a bit now, I'll make this example a bit more interesting: it will display a Mandelbrot set (using plain-text characters, so it won't look that spectacular!).

Try It Out – Using for Loops

image from book
  1. Create a new console application called Ch04Ex06 in the directory C:\BegVCSharp\Chapter4.

  2. Add the following code to Program.cs:

    static void Main(string[] args) { double realCoord, imagCoord; double realTemp, imagTemp, realTemp2, arg; int iterations; for (imagCoord = 1.2; imagCoord >= -1.2; imagCoord -= 0.05) { for (realCoord = -0.6; realCoord <= 1.77; realCoord += 0.03) { iterations = 0; realTemp = realCoord; imagTemp = imagCoord;  arg = (realCoord * realCoord) + (imagCoord * imagCoord); while ((arg < 4) && (iterations < 40)) { realTemp2 = (realTemp * realTemp) - (imagTemp * imagTemp) - realCoord; imagTemp = (2 * realTemp * imagTemp) - imagCoord; realTemp = realTemp2; arg = (realTemp * realTemp) + (imagTemp * imagTemp); iterations += 1; } switch (iterations % 4) { case 0: Console.Write("."); break; case 1: Console.Write("o"); break; case 2: Console.Write("O"); break; case 3: Console.Write("@"); break; } } Console.Write("\n"); } Console.ReadKey(); }

  3. Execute the code. The result is shown in Figure 4-8.

    image from book
    Figure 4-8

How It Works

Now, I don't want to go into too much detail about how to calculate Mandelbrot sets, but I will go through the basics to explain why you need the loops that you have used in this code. Feel free to skim through the following two paragraphs if the mathematics doesn't interest you, because it's an understanding of the code that is important here.

Each position in a Mandelbrot image corresponds to an imaginary number of the form N=x+y*i, where the real part is x, the imaginary part is y, and i is the square root of -1. The x and y coordinates of the position in the image correspond to the x and y parts of the imaginary number.

For each position on the image you look at the argument of N, which is the square root of x*x + y*y. If this value is greater than or equal to 2, you say that the position corresponding to this number has a value of 0. If the argument of N is less than 2, you change N to a value of N*N - N (giving you N = (x*xy*y-x) + (2*x*y-y)*i), and check the argument of this new value of N again. If this value is greater than or equal to 2, you say that the position corresponding to this number has a value of 1. This process continues until you either assign a value to the position on the image or perform more than a certain number of iterations.

Based on the values assigned to each point in the image you would, in a graphical environment, place a pixel of a certain color on the screen. However, because you are using a text display you simply place characters on screen instead.

Now, back to the code, and the loops contained in it.

You start by declaring the variables you will need for your calculation:

double realCoord, imagCoord; double realTemp, imagTemp, realTemp2, arg; int iterations;

Here, realCoord and imagCoord are the real and imaginary parts of N, and the other double variables are for temporary information during computation. iterations records how many iterations it takes before the argument of N (arg) is 2 or greater.

Next, you start two for loops to cycle through coordinates covering the whole of the image (using slightly more complex syntax for modifying your counters than ++ or --, a common and powerful technique):

for (imagCoord = 1.2; imagCoord >= -1.2; imagCoord -= 0.05) {    for (realCoord = -0.6; realCoord <= 1.77; realCoord += 0.03)    {

I've chosen appropriate limits to show the main section of the Mandelbrot set. Feel free to play around with these if you want to try "zooming in" on the image.

Within these two loops you have code that pertains to a single point in the Mandelbrot set, giving you a value for N to play with. This is where you perform your calculation of iteration required, giving you a value to plot for the current point.

First, you initialize some variables:

iterations = 0; realTemp = realCoord; imagTemp = imagCoord; arg = (realCoord * realCoord) + (imagCoord * imagCoord);

Next, you have a while loop to perform your iterating. You use a while loop rather than a do loop, in case the initial value of N has an argument greater than 2 already, in which case iterations = 0 is the answer you are looking for and no further calculations are necessary.

Note that I'm not quite calculating the argument fully here, I'm just getting the value of x*x + y*y and checking to see if that value is less than 4. This simplifies the calculation, because you know that 2 is the square root of 4 and don't have to calculate any square roots yourself:

while ((arg < 4) && (iterations < 40)) {    realTemp2 = (realTemp * realTemp) - (imagTemp * imagTemp)                - realCoord;    imagTemp = (2 * realTemp * imagTemp) - imagCoord;    realTemp = realTemp2;    arg = (realTemp * realTemp) + (imagTemp * imagTemp);    iterations += 1; }

The maximum number of iterations of this loop, which calculates values as detailed above, is 40.

Once you have a value for the current point stored in iterations, you use a switch statement to choose a character to output. You just use four different characters here, instead of the 40 possible values, and use the modulus operator (%) so that values of 0, 4, 8, and so on give one character; values of 1, 5, 9, and so on give another character; and so forth:

switch (iterations % 4) {    case 0:       Console.Write(".");       break;    case 1:       Console.Write("o");       break;    case 2:       Console.Write("O");       break;    case 3:       Console.Write("@");       break; }

Note that you use Console.Write() here rather than Console.WriteLine(), because you don't want to start a new line every time you output a character.

At the end of one of the innermost for loops, you do want to end a line, so you simply output an end-of-line character using the escape sequence you saw earlier:

   }    Console.Write("\n"); }

This results in each row being separated from the next and lining up appropriately.

The final result of this application, though not spectacular, is fairly impressive, and certainly shows how useful looping and branching can be.

image from book

Interrupting Loops

There are times when you want finer-grained control over the processing of looping code. C# provides four commands that help you here, three of which you've seen before in other situations:

  • break: Causes the loop to end immediately

  • continue: Causes the current loop cycle to end immediately (execution continues with the next loop cycle)

  • goto: Allows jumping out of a loop to a labeled position (not recommended if you want your code to be easy to read and understand)

  • return: Jumps out of the loop and its containing function (see Chapter 6)

The break command simply exits the loop, and execution continues at the first line of code after the loop, for example:

 int i = 1; while (i <= 10) { if (i == 6) break; Console.WriteLine("{0}", i++); } 

This code will write out the numbers from 1 to 5, because the break command causes the loop to exit when i reaches 6.

 int i; for (i = 1; i <= 10; i++)  { if ((i % 2) == 0)  continue; Console.WriteLine(i); } 

In the preceding example, whenever the remainder of i divided by 2 is zero, the continue statement stops the execution of the current cycle, and so only the numbers 1,3,5,7,9 are displayed.

The third method of interrupting a loop is to use goto as you saw earlier, for example:

 int i = 1; while (i <= 10) { if (i == 6) goto exitPoint; Console.WriteLine("{0}", i++); } Console.WriteLine("This code will never be reached."); exitPoint: Console.WriteLine("This code is run when the loop is exited using goto."); 

Note that exiting a loop with goto is legal (if slightly messy), but it is illegal to use goto to jump into a loop from outside.

Infinite Loops

It is possible, through both coding errors or design, to define loops that never end, so-called infinite loops. As a very simple example, consider the following:

 while (true) { // code in loop } 

This situation can be useful at times, and you can always exit such loops using code such as break statements or manually by using the Windows Task Manager.

However, when this occurs by accident it can be annoying. Consider the following loop, which is similar to the for loop in the last section:

 int i = 1; while (i <= 10) { if ((i % 2) == 0) continue; Console.WriteLine("{0}", i++); } 

Here, i isn't incremented until the last line of code in the loop, which occurs after the continue statement. If this continue statement is reached (which it will be when i is 2), the next loop cycle will be using the same value of i, continuing the loop, testing the same value of i, continuing the loop, and so on. This will cause the application to freeze. Note that it's still possible to quit the frozen application in the normal way, so you won't have to reboot your computer if this happens.




Beginning Visual C# 2005
Beginning Visual C#supAND#174;/sup 2005
ISBN: B000N7ETVG
EAN: N/A
Year: 2005
Pages: 278

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net