550 likes | 687 Vues
This article explores the fundamental concepts of loop invariants in programming, specifically applied to the task of multiplying two positive integers without a direct multiplication instruction. It introduces an invariant P, which helps establish a correct looping construct to achieve the multiplication using only addition, subtraction, and shifts. By delving into the logic behind constructing loops and their termination conditions, the reader will gain insights into both theoretical and practical aspects of programming fundamentals.
E N D
Writing loops: a first example Programming Fundamentals 17 Feliks Kluźniak
The Fundamental Invariance Theorem for the Iterative Construct (a.k.a. The MainTheorem of Computing Science): Let P be an invariant of the statement S. If P is true just before the loop while B do S od then not B and P will be true just after the loop, provided the loop terminates. Writing loops: a first example
Consider the problem of multiplying integers, on a machine like the A1: we have addition, subtraction, shifts, but no multiplication instruction. Writing loops: a first example
Consider the problem of multiplying integers, on a machine like the A1: we have addition, subtraction, shifts, but no multiplication instruction. So we must write a program... For simplicity, let us limit our attention only to positive integers. Writing loops: a first example
Consider the problem of multiplying integers, on a machine like the A1: we have addition, subtraction, shifts, but no multiplication instruction. So we must write a program... For simplicity, let us limit our attention only to positive integers. We can also assume none of them is zero: the computation is trivial in that case. Writing loops: a first example
Given integers A > 0 and B > 0 find an integer r such that r = A * B . Writing loops: a first example
Given integers A > 0 and B > 0 find an integer r such that r = A * B . Clearly, we will need a loop. So we must find an invariant P such that P and not C implies r = A * B and C is suitable for the condition of the loop. % P while C do ..... od % P and not C, therefore r = A * B Writing loops: a first example
Given integers A > 0 and B > 0 find an integer r such that r = A * B . Clearly, we will need a loop. So we must find an invariant P such that P and not C implies r = A * B and C is suitable for the condition of the loop. Moreover, P must be relatively easy to establish. % P while C do ..... od % P and not C, therefore r = A * B Writing loops: a first example
Given integers A > 0 and B > 0 find an integer r such that r = A * B . Clearly, we will need a loop. So we must find an invariant P such that P and not C implies r = A * B and C is suitable for the condition of the loop. Moreover, P must be relatively easy to establish. We could try to manipulate some variables a and b in such a way that P : A * B = r + a * b and b >= 0 Clearly, P and b = 0 would imply r = A * B , Writing loops: a first example
Given integers A > 0 and B > 0 find an integer r such that r = A * B . Clearly, we will need a loop. So we must find an invariant P such that P and not C implies r = A * B and C is suitable for the condition of the loop. Moreover, P must be relatively easy to establish. We could try to manipulate some variables a and b in such a way that P : A * B = r + a * b and b >= 0 Clearly, P and b = 0 would imply r = A * B , and b != 0 is an excellent boolean expression (easy to evaluate), Writing loops: a first example
Given integers A > 0 and B > 0 find an integer r such that r = A * B . Clearly, we will need a loop. So we must find an invariant P such that P and not C implies r = A * B and C is suitable for the condition of the loop. Moreover, P must be relatively easy to establish. We could try to manipulate some variables a and b in such a way that P : A * B = r + a * b and b >= 0 Clearly, P and b = 0 would imply r = A * B , and b != 0 is an excellent boolean expression (easy to evaluate), and P is very easily established. How? Writing loops: a first example
Given integers A > 0 and B > 0 find an integer r such that r = A * B . Clearly, we will need a loop. So we must find an invariant P such that P and not C implies r = A * B and C is suitable for the condition of the loop. Moreover, P must be relatively easy to establish. We could try to manipulate some variables a and b in such a way that P : A * B = r + a * b and b >= 0 Clearly, P and b = 0 would imply r = A * B , and b != 0 is an excellent boolean expression (easy to evaluate), and P is very easily established by a, b, r := A, B, 0 . Writing loops: a first example
Given integers A > 0 and B > 0 find an integer r such that r = A * B . P : A * B = r + a * b and b >= 0 . a, b, r := A, B, 0 ; % P while b != 0 do % P and b != 0 ... od % P and b = 0, therefore r = A * B Writing loops: a first example
Given integers A > 0 and B > 0 find an integer r such that r = A * B . • P : A * B = r + a * b and b >= 0 . • a, b, r := A, B, 0 ; % P • while b != 0 do • % P and b != 0 • ... • od • % P and b = 0, therefore r = A * B • So now we must write the body of the loop in such a way that: • the loop will terminate; • P will be an invariant. Writing loops: a first example
Given integers A > 0 and B > 0 find an integer r such that r = A * B . • P : A * B = r + a * b and b >= 0 . • a, b, r := A, B, 0 ; % P • while b != 0 do • % P and b != 0 • ... • od • % P and b = 0, therefore r = A * B • So now we must write the body of the loop in such a way that: • the loop will terminate; • P will be an invariant. • We can easily ensure termination by always strictly decreasing the value of b . Writing loops: a first example
Given integers A > 0 and B > 0 find an integer r such that r = A * B . • P : A * B = r + a * b and b >= 0 . • a, b, r := A, B, 0 ; % P • while b != 0 do • % P and b != 0 • ... • od • % P and b = 0, therefore r = A * B • So now we must write the body of the loop in such a way that: • the loop will terminate; • P will be an invariant. • We can easily ensure termination by always strictly decreasing the value of b . Why will this ensure termination? Writing loops: a first example
Given integers A > 0 and B > 0 find an integer r such that r = A * B . • P : A * B = r + a * b and b >= 0 . • a, b, r := A, B, 0 ; % P • while b != 0 do • % P and b != 0 • ... • od • % P and b = 0, therefore r = A * B • So now we must write the body of the loop in such a way that: • the loop will terminate; • P will be an invariant. • We can easily ensure termination by always strictly decreasing the value of b . Because, if we preserve P, b is bounded from below! Writing loops: a first example
Given integers A > 0 and B > 0 find an integer r such that r = A * B . • P : A * B = r + a * b and b >= 0 . • a, b, r := A, B, 0 ; % P • while b != 0 do • % P and b != 0 • ... • od • % P and b = 0, therefore r = A * B • So now we must write the body of the loop in such a way that: • the loop will terminate; • P will be an invariant. • We can easily ensure termination by always strictly decreasing the value of b . For example, by subtracting 1... Writing loops: a first example
Given integers A > 0 and B > 0 find an integer r such that r = A * B . P : A * B = r + a * b and b >= 0 . a, b, r := A, B, 0 ; % P while b != 0 do % P and b != 0 b := b – 1 ; % ensures termination ... .... od % P and b = 0, therefore r = A * B Writing loops: a first example
Given integers A > 0 and B > 0 find an integer r such that r = A * B . P : A * B = r + a * b and b >= 0 . a, b, r := A, B, 0 ; % P while b != 0 do % P and b != 0 b := b – 1 ; % ensures termination (and violates P !) .... od % P and b = 0, therefore r = A * B Writing loops: a first example
Given integers A > 0 and B > 0 find an integer r such that r = A * B . P : A * B = r + a * b and b >= 0 . a, b, r := A, B, 0 ; % P while b != 0 do % P and b != 0 b := b – 1 ; % ensures termination (and violates P !) .... od % P and b = 0, therefore r = A * B Now, how do we restore P ? Writing loops: a first example
Given integers A > 0 and B > 0 find an integer r such that r = A * B . P : A * B = r + a * b and b >= 0 . a, b, r := A, B, 0 ; % P while b != 0 do % P and b != 0 b := b – 1 ; % ensures termination (and violates P !) .... od % P and b = 0, therefore r = A * B Now, how do we restore P ? We have almost no choice, but to use: r + a * b = (r + a) + a * (b – 1) Writing loops: a first example
Given integers A > 0 and B > 0 find an integer r such that r = A * B . P : A * B = r + a * b and b >= 0 . a, b, r := A, B, 0 ; % P while b != 0 do % P and b != 0 b := b – 1 ; % ensures termination (and violates P !) r := r + a % restores P od % P and b = 0, therefore r = A * B Writing loops: a first example
Given integers A > 0 and B > 0 find an integer r such that r = A * B . P : A * B = r + a * b and b >= 0 . a, b, r := A, B, 0 ; % P while b != 0 do % P and b != 0 b := b – 1 ; % ensures termination (and violates P !) r := r + a % restores P od % P and b = 0, therefore r = A * B a b r 2 5 0 Writing loops: a first example
Given integers A > 0 and B > 0 find an integer r such that r = A * B . P : A * B = r + a * b and b >= 0 . a, b, r := A, B, 0 ; % P while b != 0 do % P and b != 0 b := b – 1 ; % ensures termination (and violates P !) r := r + a % restores P od % P and b = 0, therefore r = A * B a b r 2 5 0 2 4 2 Writing loops: a first example
Given integers A > 0 and B > 0 find an integer r such that r = A * B . P : A * B = r + a * b and b >= 0 . a, b, r := A, B, 0 ; % P while b != 0 do % P and b != 0 b := b – 1 ; % ensures termination (and violates P !) r := r + a % restores P od % P and b = 0, therefore r = A * B a b r 2 5 0 2 4 2 2 3 4 Writing loops: a first example
Given integers A > 0 and B > 0 find an integer r such that r = A * B . P : A * B = r + a * b and b >= 0 . a, b, r := A, B, 0 ; % P while b != 0 do % P and b != 0 b := b – 1 ; % ensures termination (and violates P !) r := r + a % restores P od % P and b = 0, therefore r = A * B a b r 2 5 0 2 4 2 2 3 4 2 2 6 Writing loops: a first example
Given integers A > 0 and B > 0 find an integer r such that r = A * B . P : A * B = r + a * b and b >= 0 . a, b, r := A, B, 0 ; % P while b != 0 do % P and b != 0 b := b – 1 ; % ensures termination (and violates P !) r := r + a % restores P od % P and b = 0, therefore r = A * B a b r 2 5 0 2 4 2 2 3 4 2 2 6 2 1 8 Writing loops: a first example
Given integers A > 0 and B > 0 find an integer r such that r = A * B . P : A * B = r + a * b and b >= 0 . a, b, r := A, B, 0 ; % P while b != 0 do % P and b != 0 b := b – 1 ; % ensures termination (and violates P !) r := r + a % restores P od % P and b = 0, therefore r = A * B a b r 2 5 0 2 4 2 2 3 4 2 2 6 2 1 8 2 0 10 Writing loops: a first example
Given integers A > 0 and B > 0 find an integer r such that r = A * B . P : A * B = r + a * b and b >= 0 . a, b, r := A, B, 0 ; % P while b != 0 do % P and b != 0 b := b – 1 ; % ensures termination (and violates P !) r := r + a % restores P od % P and b = 0, therefore r = A * B This algorithm is not very surprising: a * b = a + a + .... + a b times Writing loops: a first example
Given integers A > 0 and B > 0 find an integer r such that r = A * B . P : A * B = r + a * b and b >= 0 . a, b, r := A, B, 0 ; % P while b != 0 do % P and b != 0 b := b – 1 ; % ensures termination (and violates P !) r := r + a % restores P od % P and b = 0, therefore r = A * B This algorithm is not very surprising. It is also extremely inefficient! Consider, e.g., A = 1 and B = 32 000. Writing loops: a first example
Given integers A > 0 and B > 0 find an integer r such that r = A * B . P : A * B = r + a * b and b >= 0 . a, b, r := A, B, 0 ; % P while b != 0 do % P and b != 0 b := b – 1 ; % ensures termination (and violates P !) r := r + a % restores P od % P and b = 0, therefore r = A * B This algorithm is not very surprising. It is also extremely inefficient! Consider, e.g., A = 1 and B = 32 000. We must do better! When did we last make a decision? Writing loops: a first example
Given integers A > 0 and B > 0 find an integer r such that r = A * B . P : A * B = r + a * b and b >= 0 . a, b, r := A, B, 0 ; % P while b != 0 do % P and b != 0 b := b – 1 ; % ensures termination (and violates P !) .... od % P and b = 0, therefore r = A * B Can we decrease b in a more clever way? (The difficulty is in restoring P.) Writing loops: a first example
Given integers A > 0 and B > 0 find an integer r such that r = A * B . P : A * B = r + a * b and b >= 0 . a, b, r := A, B, 0 ; % P while b != 0 do % P and b != 0 b := b – 1 ; % ensures termination (and violates P !) .... od % P and b = 0, therefore r = A * B If b is an even number, then we can divide it by 2 simply by shifting! Writing loops: a first example
Given integers A > 0 and B > 0 find an integer r such that r = A * B . P : A * B = r + a * b and b >= 0 . a, b, r := A, B, 0 ; % P while b != 0 do % P and b != 0 b := b – 1 ; % ensures termination (and violates P !) .... od % P and b = 0, therefore r = A * B If b is an even number, then we can divide it by 2 simply by shifting! How would we then restore P ? b:= b div 2 Writing loops: a first example
Given integers A > 0 and B > 0 find an integer r such that r = A * B . P : A * B = r + a * b and b >= 0 . a, b, r := A, B, 0 ; % P while b != 0 do % P and b != 0 b := b – 1 ; % ensures termination (and violates P !) .... od % P and b = 0, therefore r = A * B If b is an even number, then we can divide it by 2 simply by shifting! How would we then restore P ? b:= b div 2 ; a := a * 2 Writing loops: a first example
Given integers A > 0 and B > 0 find an integer r such that r = A * B . P : A * B = r + a * b and b >= 0 . a, b, r := A, B, 0 ; % P while b != 0 do % P and b != 0 b := b – 1 ; % ensures termination (and violates P !) .... od % P and b = 0, therefore r = A * B If b is an even number, then we can divide it by 2 simply by shifting! How would we then restore P ? b:= b div 2 ; a := a * 2 a * b = (a * 2) * (b / 2) and b / 2 = b div 2 if b is even! Writing loops: a first example
Given integers A > 0 and B > 0 find an integer r such that r = A * B . P : A * B = r + a * b and b >= 0 . a, b, r := A, B, 0 ; % P while b != 0 do % P and b != 0 if b is odd then % just check the lowest bit b := b – 1; r := r + a % P else b := b div 2 ; % just a shift a := a * 2 % just a shift, restores P fi % P od % P and b = 0, therefore r = A * B
Given integers A > 0 and B > 0 find an integer r such that r = A * B . P : A * B = r + a * b and b >= 0 . a, b, r := A, B, 0 ; % P while b != 0 do % P and b != 0 if b is odd then % just check the lowest bit b := b – 1; r := r + a % P else b := b div 2 ; % just a shift a := a * 2 % just a shift, restores P fi % P od % P and b = 0, therefore r = A * B • a b r • 5 0
Given integers A > 0 and B > 0 find an integer r such that r = A * B . P : A * B = r + a * b and b >= 0 . a, b, r := A, B, 0 ; % P while b != 0 do % P and b != 0 if b is odd then % just check the lowest bit b := b – 1; r := r + a % P else b := b div 2 ; % just a shift a := a * 2 % just a shift, restores P fi % P od % P and b = 0, therefore r = A * B • a b r • 5 0 • 2 4 2
Given integers A > 0 and B > 0 find an integer r such that r = A * B . P : A * B = r + a * b and b >= 0 . a, b, r := A, B, 0 ; % P while b != 0 do % P and b != 0 if b is odd then % just check the lowest bit b := b – 1; r := r + a % P else b := b div 2 ; % just a shift a := a * 2 % just a shift, restores P fi % P od % P and b = 0, therefore r = A * B • a b r • 5 0 • 2 4 2 • 2 2
Given integers A > 0 and B > 0 find an integer r such that r = A * B . P : A * B = r + a * b and b >= 0 . a, b, r := A, B, 0 ; % P while b != 0 do % P and b != 0 if b is odd then % just check the lowest bit b := b – 1; r := r + a % P else b := b div 2 ; % just a shift a := a * 2 % just a shift, restores P fi % P od % P and b = 0, therefore r = A * B • a b r • 5 0 • 2 4 2 • 2 2 • 1 2
Given integers A > 0 and B > 0 find an integer r such that r = A * B . P : A * B = r + a * b and b >= 0 . a, b, r := A, B, 0 ; % P while b != 0 do % P and b != 0 if b is odd then % just check the lowest bit b := b – 1; r := r + a % P else b := b div 2 ; % just a shift a := a * 2 % just a shift, restores P fi % P od % P and b = 0, therefore r = A * B • a b r • 5 0 • 2 4 2 • 2 2 • 1 2 • 8 0 10
Given integers A > 0 and B > 0 find an integer r such that r = A * B . P : A * B = r + a * b and b >= 0 . a, b, r := A, B, 0 ; % P while b != 0 do % P and b != 0 if b is odd then % just check the lowest bit b := b – 1; r := r + a % P else b := b div 2 ; % just a shift a := a * 2 % just a shift, restores P fi % P od % P and b = 0, therefore r = A * B In general this is much faster! What is the maximum number of iterations?
Given integers A > 0 and B > 0 find an integer r such that r = A * B . P : A * B = r + a * b and b >= 0 . a, b, r := A, B, 0 ; % P while b != 0 do % P and b != 0 if b is odd then % just check the lowest bit b := b – 1; r := r + a % P else b := b div 2 ; % just a shift a := a * 2 % just a shift, restores P fi % P od % P and b = 0, therefore r = A * B In general his is much faster! 39 (for a 20 bit word)
Given integers A > 0 and B > 0 find an integer r such that r = A * B . P : A * B = r + a * b and b >= 0 . a, b, r := A, B, 0 ; % P while b != 0 do % P and b != 0 if b is odd then % just check the lowest bit b := b – 1; r := r + a % P else b := b div 2 ; % just a shift a := a * 2 % just a shift, restores P fi % P od % P and b = 0, therefore r = A * B 39 (for a 20 bit word) Can we make it even faster?
Given integers A > 0 and B > 0 find an integer r such that r = A * B . P : A * B = r + a * b and b >= 0 . a, b, r := A, B, 0 ; % P while b != 0 do % P and b != 0 if b is odd then % just check the lowest bit b := b – 1; r := r + a % P fi; b := b div 2 ; % just a shift a := a * 2 % just a shift,P od % P and b = 0, therefore r = A * B b must be even ! Writing loops: a first example
Given integers A > 0 and B > 0 find an integer r such that r = A * B . P : A * B = r + a * b and b >= 0 . a, b, r := A, B, 0 ; % P while b != 0 do % P and b != 0 if b is odd then % just check the lowest bit b := b – 1; r := r + a % P fi; b := b div 2 ; % just a shift a := a * 2 % just a shift,P od % P and b = 0, therefore r = A * B What if b = 0 ? Writing loops: a first example
Given integers A > 0 and B > 0 find an integer r such that r = A * B . P : A * B = r + a * b and b >= 0 . a, b, r := A, B, 0 ; % P while b != 0 do % P and b != 0 if b is odd then % just check the lowest bit b := b – 1; r := r + a % P fi; b := b div 2 ; % just a shift a := a * 2 % just a shift,P od % P and b = 0, therefore r = A * B What if b = 0 ? We make use of the fact that: 0 div 2 = 0 a * 0 = a * 2 * 0 Writing loops: a first example
Given integers A > 0 and B > 0 find an integer r such that r = A * B . P : A * B = r + a * b and b >= 0 . a, b, r := A, B, 0 ; % P while b != 0 do % P and b != 0 if b is odd then % just check the lowest bit b := b – 1; r := r + a % P fi; b := b div 2 ; % just a shift a := a * 2 % just a shift,P od % P and b = 0, therefore r = A * B This is exactly the algorithm we use when multiplying by hand! Writing loops: a first example