You can think of coding as writing instructions for a computer to follow. Let's say I want my computer to print out each of the numbers from 1 to 100. In Python, printing a number is easy:
print(1)
This will print the number 1. Printing all the numbers from 1 to 100 is a little more challenging though. Here's one way:
print(1) print(2) print(3) print(4) print(5) ...
That will take a long time to write, and physicists are lazy! This is a problem. We often want computers to repeat the same instruction (or a very similar instruction) many times in a row. Luckily, there is a solution. What do you think the following code does?
i = 1 while i <= 100: print(i) i = i + 1
You guessed it–in just a few lines, this code prints the numbers from 1 to 100. Let's break down what it's doing.
Here's another example of a while loop:
# Initialize position pos = vec(0, 0, 0) # Initialize velocity v = vec(1, 0, 0) # Counter variable t = 0 # Increment amount dt = 1 # Loop! while t <= 200: # Conditional pos += v*dt # Operation t += dt # Increment
All of the lines before the while loop are setting up variables used in the while loop: position, velocity, time, and change in time. These lines will only run once, before the while loop starts. Everything “inside” the while loop (shown in Python by the indent) will run over and over again as long as the conditional is true.
The conditional is evaluated every time before the while loop runs. In the case of while loops, the conditional is whatever comes after “while” in the top line of the loop. It should be a statement that can be evaluated by the computer as either True or False. These statements usually contain a conditional operator: < (less than), > (greater than), == (equal to), ⇐ (less than or equal), or >= (greater than or equal).
Usually, some kind of counter variable (in the above example it's time) is included in the conditional of a while loop. This counter variable is adjusted within the loop, and specifies the range of values that the loop will operate over. You can think of the above loop as having bounds, similarly to an integral, from time = 0 to time = 200.
We usually call each “run” or execution of a loop an iteration. How much does the time increase during each iteration of the loop above?
Think about calculating the electric potential in each square of a chess board. You could randomly choose squares to calculate until you finished the board, or work through row-by-row. Computers are good at working systematically, so let's go with the systematic row-by-row approach. We're going to be doing the same thing (checking electric potential) over and over again, so this sounds like a good application for loops. Numbering each row and column in a chess board gives a grid that looks like this: How could we use a while loop to generate the position of each square in the grid? It's tempting to do the following:
row = 1 column = 1 while row <= 8 and column <= 8: # Calculate E field for (row, column) row += 1 column += 1
Because row and column always increase by the same amount, this will only calculate the E field for boxes (1, 1), (2, 2), (3, 3), and so on. This doesn't work.
Instead, we need to use a nested while loop:
row = 1 while row <= 8: column = 1 while column <= 8: # Calculate E field for (row, column) column += 1 row += 1
In the above code, there are two separate while loops, with different conditional statements. The outer while loop (looping over rows) will only execute 8 times. Each time the outer loop executes, the inner loop (columns) will also execute 8 times. Together, the two loops will cover all 8 * 8 = 64 boxes in the chess board.
When you write code with a nested loop, it's important to carefully consider where each line of code belongs. In the above code, the column variable will be set to 1 eight times, moving back to the first column in each new row. The row variable is also only increased eight times, because it is not within the inner loop. If we forget to set the column variable back to 1, or increase the row variable 64 times, the code will not do what we intend.