# Example: systematic construction of an integer square root program ```Example: systematic construction of an integer square
root program
W. Drabent
13 May 2004
We want to construct a program computing the integer square root of a
non-negative integer n. In other words, the program has to be totally correct
w.r.t. precondition P = n ≥ 0 and postcondition Q = (x2 ≤ n &lt; (x + 1)2 ).
(The latter also says that x will contain the result). My intuition tells me
that we should try to use a loop. So a skeleton of our program is
{ P } ?? ; while b do ?? { ⇓ Q }.
(I will not write ⇓ below, but remember – we are dealing with total correctness).
The most important thing in a loop is its invariant. A typical way of
obtaining a loop invariant is to weaken the postcondition. It should be easy
to obtain the invariant from the precondition and the postcondition from the
invariant. In the previous example we constructed the invariant by removing
n &lt; (x + 1)2 from Q. Here we introduce a new variable y and take
I = ( x2 ≤ n &lt; y 2 ∧ 0 ≤ x &lt; y, )
as the invariant.1 The intuition behind I is that the number we are going
to compute is somewhere between x and y.
It is good to remember the proof rule for while which we use:
{b ∧ I ∧ t=z } S {⇓I ∧ t&lt;z }
{ I } while b do S { ⇓ &not;b ∧ I }
if I ⇒ t ≥ 0
(where t – the bound function – is an integer expression and z is a variable
that does not appear in P, b, t or S).
Q, I and the proof rule for while suggest the choice of b, as it is necessary
that &not;b ∧ I implies Q. We achieve this by taking
b = (y 6= x+1).
P does non imply I, so the loop requires initialization. We are looking
for a statement S0 satisfying { P } S0 { I }. It is easy to check that S0 =
(x := 0; y := n+1) does the work.
1
Strictly speaking, I is not weaker than Q (in other words, Q does not imply I). We
first strengthened Q by introducing y, obtaining Q1 = (x2 ≤ n &lt; y 2 ∧ y = x + 1). This
implies 0 ≤ x &lt; y, so Q1 is equivalent to Q1 ∧ 0 ≤ x &lt; y. Then we weakened the last
formula by removing y = x + 1.
1
This is the current version of our program
{ P }(x := 0; y := n+1); { I } while b do
(1)
({ b| ∧ I {z
∧ t = z} } S { I ∧ t &lt; z }) { Q }.
P0
Now we are looking for a suitable bound function t. It should be ≥ 0 and
it should decrease at each repetition of the loop. Our intention is that the
loop shrinks the interval [x..y) containing the solution until the solution is
found. So a good candidate for t is the size of this interval:
t = y − x.
Note that the invariant indeed implies t ≥ 0.
It remains to construct the loop body S satisfying the stated pre- and
postcondition. S has to decrease t. We want to be efficient, so we use binary
search. The future solution is somewhere between x and y. We halve the
interval [x..y) and choose that half that preserves the invariant (in other
words, contains the solution).
As there are two cases, S is likely to be a conditional statement. Halving
will be done by setting either x or y to the midpoint (x+y)&divide;2 (where &divide; is
the integer division, e.g. 7 &divide; 2 = 3). We abbreviate (x+y)&divide;2 by A. Together
we have
S = if b0 then y := A else x
{z A}
| :=
| {z }
S2
S1
The postcondition for both S1 and S2 is I ∧ t&lt;z. The axiom [ass] gives
2
{x
≤ n &lt; A2 ∧ 0 ≤{zx &lt; A ∧ A−x &lt; z} } y := A { I ∧ t&lt;z }
|
(2)
R1
2
2
{ A ≤ n &lt; y ∧ 0 ≤ A &lt; y ∧ y−A &lt; z } x := A { I ∧ t&lt;z }
|
{z
}
R2
(3)
We want to apply the rule [if], but this requires the preconditions to be of
the form b0 ∧ R and &not;b0 ∧ R. So we are looking for such conditions implying,
respectively, R1 and R2 . A good candidate for b0 is n &lt; A2 , as n &lt; A2 occurs
in R1 and A2 ≤ n occurs in R2 ). Taking b0 = n &lt; A2 and
R = x2 ≤ n &lt; y 2 ∧ 0 ≤ x &lt; A &lt; y ∧ A−x &lt; z ∧ y−A &lt; z
we see that indeed b0 ∧ R implies R1 and &not;b0 ∧ R implies R2 .
From (2), (3) by rule [cons] we obtain
{ b0 ∧ R } y := A { I ∧ t&lt;z }
{ &not;b0 ∧ R } x := A { I ∧ t&lt;z }
2
(4)
(5)
and then
{ R } S { I ∧ t&lt;z }
We are almost ready, but the required precondition for S is P0 (see (1)). We
will show that P0 implies R, then applying [cons] gives
{ P0 } S { I ∧ t&lt;z }
and completes the construction of the program (1) and proof of its correctness.
Back to the unproven implication P0 ⇒ R. Remember that
P0 = y 6= x+1 ∧ x2 ≤ n &lt; y 2 ∧ 0 ≤ x &lt; y ∧ y−x = z.
Compare this with R. You see that it remains to show that P0 implies
x &lt; A &lt; y and A−x &lt; z ∧ y−A &lt; z. (This says that both parts [x..A) and
[A..y), into which we divide the interval [x..y), are smaller than [x..y), whose
length is z. This sounds obvious but, for instance, if y = x + 1 then A = x).
From x &lt; y and y 6= x+1 we have x+2 ≤ y. This implies2 x &lt; A &lt; y.
From this and y − x = z we obtain3 the required inequalities.
END OF THE PROOF &amp; CONSTRUCTION
Our work can be summarized in the following proof outline.
{n ≥ 0}
x := 0; y := n+1;
{ invariant: I }
{ boundfunction: y − x }
while y 6= x + 1 do ( { b ∧ I ∧ y−x = z }
|
{z
b
}
{ x2 ≤ n &lt; (x + 1)2 }
|
{z
P0
}
{R}
if n &lt; A2 then { n&lt;A2 ∧ R }
{ R1 }
y := A
else { &not;(n&lt;A2 ) ∧ R }
{ R2 }
x := A
{ I ∧ y−x &lt; z } )
2
How? x + x + 2 ≤ x + y, hence x + 1 ≤ (x + y) &divide; 2 = A. Similarly, x + y ≤ y − 2 + y,
hence A ≤ y − 1.
3
How? From A &lt; y we have A − x &lt; y − x = z. From x &lt; A we have y − A &lt; y − x = z.
3
```