/* PROOF OF CORRECTNESS: FACTORIAL(X): compute X! = 1*2*3*...*X Proof of Correctness is similar to Mathematical Induction. If we run the factorial program below, either by computer or by hand: Trace factorial(4)=24: f y (y-1)! ---------------- 1 1 1 1 2 1 2 3 2 6 4 6 24 5 24 1. f=(y-1)! initially (similar to the "base") and after every iteration (similar to "step") 2. Our "eyes" tell us that y = x + 1 after the loop exits. In order to prove this, make this LOOP INVARIANT: f = (y-1)! and y <= x + 1 This is a statement of truth, which holds the first time the loop is encountered, and with each iteration. 3. The INVARIANT above combines with the EXIT condition of the loop (i.e. NOT y <= x implies y > x) yielding y = x + 1. This leads to f = (y-1)! = x! (the POST-CONDITION, the purpose of the function). */ #include int factorial(int x) { int f, y; // PRE-CONDITION: x >= 0 // code does not work for negative integers // initialization code y = 1; // x >= 0 and y = 1 // simple statement of truth f = 1; // x >= 0 and y = 1 and f = 1 // INVARIANT: f = (y-1)! and y <= x + 1 // the initialization code insures that the INVARIANT // is true the first time. The loop code below will // insure that the INVARIANT is true with each iteration. while (y <= x) { // f = (y-1)! and y <= x // nothing has changed from the above but we can now use the tighter // bound of the while condition. This will be important when y changes // below. f = f * y; // f = y! and y <= x // f use to be (y-1)! but now it is y! because of the multiplication y = y + 1; // INVARIANT: f =(y-1)! and y <= x + 1 // f was just made y! but now y is larger, so f is // only (y-1)! again. We had y <= x but now y is larger // so we go back to the looser bound: y <= x + 1. // The INVARIANT holds again and this location is the same // code location as the top of the loop. } // end while // The loop exits and these are true: // INVARIANT (really same code location as top of loop) // NOT while condition (i.e. NOT y <= x implies y > x) // INVARIANT: f = (y-1)! and y <= x + 1 and EXIT: y > x // f = (y-1)! and y = x + 1 // how can y <= x + 1 and y > x at the same time? Only by y = x + 1. // What did your "eyes" tell you about the loop index y? // You expect y to be x + 1, and it's been proved . // POST-CONDITION: f = x! // the purpose of the function return f; } int main() { printf("factorial(4)=%d\n",factorial(4)); } /* In summary, the INVARIANT is a statement of truth which will helps to prove that the loop performs the proper computation. Usually, the INVARIANT consists of two parts: partial computation AND restriction on loop index The partial computation for factorial above is: f = (y-1)! That is, f holds the partial result that a factorial has been computed but only as far as y-1. The restriction on the loop index above is: y <= x + 1. This combined with the EXIT CONDITION y > x prove what our eyes already knew: y = x + 1. Hence, f=(y-1)!=x! In general, the code will look like: // intro code // INVARIANT: partial computation using index AND restriction on loop index while (cond) { // loop code INVARIANT: partial computation using index AND restriction on loop index } INVARIANT: partial computation using index AND restriction on loop index AND EXIT: !cond INVARIANT: partial computation using index AND exact value of loop index ("eyeballs") POST: final computation */