10B. Loop Invariants

Here is the power function that we developed on the preceding page.

  int power(int x, int n)
  {
    int k = 1;
    int p = x;
    while(k != n)
    {
      p = p * x;
      k = k + 1;
    }
    return p;
  }
The pre-simulation for power with x = 3 and n = 4 went as follows.
     p    k    x     n
     3    1    3     4    (p = x1)
     9    2               (p = x2)
    27    3               (p = x3)
    81    4               (p = x4)

As noted, at every line, looking at the current values of p and k, p = xk. We say that assertion p = xk is a loop invariant of this loop. A loop invariant is an assertion about the current values of the variables that is true whenever the program is at the beginning of the loop. It cannot talk about prior values of the variables or what their values will be in the future.

What is the point of a loop invariant? Partly, we made implicit use of the loop invariant in designing the loop, by choosing to keep p = xk true at each line of the pre-simulation.

Another use of loop invariants is as follows. If the loop invariant is true at every line of the hand simulation, then it must be true for the last line. But in the last line, we know that k = n. (If kn, the loop keeps going.) Putting those two facts together:

p = xk
k = n

Replacing k by equal value n in the first equation gives

p = xn

That is a bare-bones proof that our algorithm is correct, and increases our confidence that our function definition is correct.

A loop invariant for the gcd function

Let's look at the gcd function from the previous page. Here is the definition that was derived.

  int gcd(int x, int y)
  {
    int m = x;
    int n = y;
    while(n != 0)
    {
      int oldm = m;
      int oldn = n;
      m = oldn;
      n = oldm % oldn;
    }
    return m;
  }

Here is a hand simulation of gcd(15, 40) (so x = 15 and y = 40, and they don't change during the loop).

      m     n     x     y
     15    40    15    40
     40    15
     15    10
     10     5
      5     0

Can you find an interesting loop invariant for the loop in the gcd function? Remember that it must only concern the current values of x, y, m and n. (Look for it now; the answer is in the next paragraph.)

A useful invariant for the gcd loop is

gcd(m, n) = gcd(x, y)

That holds for every line of the hand simulation. So it must hold for the last line, where n = 0. That is:

gcd(m, 0) = gcd(x, y)

Since Euclid tells us that gcd(m, 0) = m, it is clear that m is the correct result when the loop is done.