Computer Programming II
(TA C252, Lect 6)
Today’s Agenda
Linear search
Unordered List
Ordered List
Binary search
Correctness issues
Friday, September 4, 2009 2
Linear search in ordered
sequence
10 15 18 21 25 33 41 53 55
Friday, September 4, 2009 3
Algorithm for Linear search
current=1;
while (current <=N) do
if (A[current] = = x) return current;
if(A[current]>x) return -1; // if sequence is ordered
current++;
endwhile;
return -1;
Friday, September 4, 2009 4
Divide and Conquer Example
2
Problem: Searching an Ordered list
Given an ordered sequence of N elements,
find whether there exists an element
‘x’ in the sequence
Friday, September 4, 2009 5
Binary Search Algorithm
low = 1; high = N;
while (low < =high) do
mid = (low + high) /2;
if (A[mid] = = x) return mid;
else if (A[mid] < x) low = mid +1;
else high = mid – 1;
endwhile;
return -1;
Friday, September 4, 2009 6
Finding 55
10 15 18 21 25 33 41 53 55
low mid high
33 41 53 55
low mid high
53 55 55
low & mid high low, mid & high
Friday, September 4, 2009 7
Finding 22
10 15 18 21 25 33 41 53 55
low mid high
10 15 18 21
low mid high 21
21 25
18 21
low, mid and high
high & mid low
low & mid high
Friday, September 4, 2009 8
Correctness Issues
Motivation
Modules, Contracts, Invariants
Tests and Test Cases
Friday, September 4, 2009 9
What is correctness?
Design Correctness
Solution (design) meets requirements
Verified offline (often on paper)
Proof arguments
Implementation Correctness
Implementation (program code) matches design
Verified online (often by execution)
Tests and Test Cases
Friday, September 4, 2009 10
What is Correctness?
Output of Design step: Program Design
High level solution to problem
Consists of modules and module interconnections
Modules are solutions to sub-problems
Interconnections capture ways to combine sub-
solutions
Friday, September 4, 2009 11
Design Correctness
Design Correctness involves
Module correctness (for each module)
Combination correctness
Design Correctness is verified by correctness
arguments:
Establish Module Correctness
Verify contracts between modules.
Friday, September 4, 2009 12
Module Correctness
Often reduces to algorithm correctness:
Algorithm will terminate
Algorithm will produce required result if and when
it terminates.
Both arguments are fairly easy for “straight-
line” programs – i.e., no loops.
Friday, September 4, 2009 13
Module Correctness
Problem: Given a, b, and c, solve quadratic
equation –
a*x2 + b*x + c = 0
Friday, September 4, 2009 14
Module Correctness
Solution: Define function quad(a, b, c, sign) as
disc = b*b – 4*a*c;
if (sign) return (-b + sqrt(disc)) / (2 *a);
else return (-b – sqrt(disc)) / (2*a);
Friday, September 4, 2009 15
Module Correctness
Termination:
if sqrt terminates, this function terminates.
Valid results:
if sqrt is correct then this returns correct value.
How do we handle the “if” conditions above?
Contracts
Friday, September 4, 2009 16
Inter-Module Correctness
Whoever writes sqrt function, specifies input-
output contract:
/* Pre-condition: m > 0
Post-condition: return n such that
|n * n – m| / m < .01
*/
float sqrt(float m) argument must be +ve definite
{
Friday, September 4, 2009 17
Module Correctness for
sqrt(x)
R = m/2
Err = abs(R * R – m)/m
Err < .01? Yes return R
No
R= (R + m/R)/2
Err = abs(R*R – m)/m
Friday, September 4, 2009 18
float sqrt (float m) /*
{ Pre condition:
float R=m/2; m>0
float Err= (R*R – m)/m; Post condition:
while (Err >= 0.01) R = sqrt(m) (with a
{ relative error less than
1%)
R= (R + m/R)/2;
Err < 0.01
Err=(R*R – m)/m;
*/
}
return R;
}
Friday, September 4, 2009 19
Inter-Module Correctness
Observation:
Precondition m > 0
This is required for sqrt to be correct (or may be
even to terminate).
So, quad module must guarantee before invocation
of sqrt:
disc > 0
Friday, September 4, 2009 20
Inter-Module Correctness
The previous contract may propagate up:
/* Pre-condition: b*b > 4*a*c
Post-condition: return x such that
| a*x*x + b*x + c | <= epsilon
*/
float quad(float a, float b, float c, int sign)
{
Friday, September 4, 2009 21
Function interfacing errors minimized
due to the
Pre conditions and Post conditions.
Why do need correctness ?
Testing will be easy
Helpful to the third party users
Correct way a writing a function from now on:
/* Pre-condition : ……. */
/* Post-condition: …….*/
<Function >
Friday, September 4, 2009 22
Correctness of Algorithms
After writing a program,
test on sets of sample data.
Choose sample data to test the correctness in
extreme cases.
Testing on sample data can’t give perfect
confidence that the program is correct.
Need a proof that the program is correct.
Many methods of proofs for program
correctness are based on induction.
Friday, September 4, 2009 23
Pre-conditions and Post-conditions
The predicate describing the initial state is called the
pre-condition of the algorithm.
The predicate describing the final state is called the
post-condition of the algorithm.
Example:
In an algorithm which computes
the product of prime numbers p1, p2, …, pn:
pre-condition: The input variables p1, p2, …, pn
are prime numbers.
post-condition: The output variable q equals
p1·p2· …·pn .
Friday, September 4, 2009 24
How the post conditions are
met?
- A revisit to single-step routines
Take the post condition, push it up, one step at a time
Infer the pre-condition
Example: 1 Example 2: Swap 2 Numbers
/*Precondition: x and y are integer
/* pre condition: x < 2 values
post condition x< 10 */ Post condition: x and y swapped
int compute (int x) Example x=6, y=8 */
{ void swap (int x, int y)
int y =3*x+1; {
x=y+3; x=x+y;
return x; y=x-y;
} x=x-y;
}
Friday, September 4, 2009 25
Correctness for Conditional statements
Example 1: Example 2: Largest of 3 numbers
//Post condition: y >0 // Precondition: a, b, and c are
integer values
//Pre condition: ???
//Post condition: result is the largest
int fun1(int x, int y) of a, b and c
{ int large3(int a, int b, int c)
if(x >0) {
y =y-1; int result;
else if((a>=b) && (a>=c))
y =y+1; result =a;
return y; else if ((b>=a) && (b>=c))
} result =b;
else
result =c;
return result;
}
Friday, September 4, 2009 26
Loop Invariants: Method to
prove correctness of loops
Loop has the following appearance:
[pre-condition for loop]
while (Guard)
[Statements in body of loop. None
contain branching statements that
lead outside the loop.]
end while
[post-condition for loop]
Friday, September 4, 2009 27
Loop-Invariant
Every loop has a pre-condition and post-condition
There is some condition G
True the loop will continue and
False the loop terminates
Some condition I remains constant in loop
Correct before loop begins
In each iteration of loop
After loop terminates
Friday, September 4, 2009 28
Loop Invariance Example 1
/* Pre –condition : N >=0 */
/* Post –condition: fact =N! and i>0*/
int factorial (int N)
{
int fact =1; int i=1;
/* fact = i-1! and i>0 */
while (i<=N)
{
fact = fact * i;
i++;
/* fact = i-1! and i>0 */
}
/* fact = i-1! and i>0 */
return fact;
}
Loop Invariant: fact=i-1! and i>0
Friday, September 4, 2009 29
What is a loop invariant?
Property that is maintained “invariant” by iterations
in a loop.
Captures progressive computational role of the loop and
remaining true before and after the loop irrespective of how
many times the loop is executed
How is it used:
Verify before the loop
Verify each iteration preserves it.
Property on termination of loop must result in “what is
expected”
Friday, September 4, 2009 30
Using Loop Invariance
Verify the following properties
n Basis property: The pre-condition implies that I is true before
the first iteration of the loop
• fact = i-1! and i>0
n Inductive property: If guard G and I are true before an
iteration, then I is true after the iteration.
• fact = i-1! and i>0 is preserved by the body of the loop
n Eventual falsity of Guard: After finite number of iterations of
the loop, the guard G becomes false. [Termination condition]
• i eventually becomes > N
n Correctness of the Post-Condition: Q: (NOT G) and I
implies the post-condition. {Q} ={I and ! G }
when termination occurs, i.e., i=N+1;
fact=((N+1)-1)! which is same as post-condition fact=N!
Friday, September 4, 2009 31
Loop Invariance Example
// Precondition: N>=0
1_Part
// Post condition: fact = N! and {
2
int factorial (int N)
i>=0 int fact =1; int i=N;
/* N! = fact * i! and i>=0 */
while (i>0)
{
fact = fact * i;
Loop Invariant: i––;
N!=fact * i! and i>=0 /* N! = fact * i! and i>=0 */
}
/* N! = fact * i! and i>=0 */
return fact;
}
Friday, September 4, 2009 32
Module Correctness for
sqrt(x)
R = x/2
Err = abs(R * R – x)/x
Err < .01? Yes return R
No
R= (R + x/R)/2
Err = abs(R*R – x)/x
Friday, September 4, 2009 33
Loop Invariance Example 2
/* float sqrt (float m)
Pre condition: {
m>0 float R=m/2;
Post condition: float Err= (R*R – m)/m;
R = sqrt(m) (with a relative while (Err >= 0.01)
error less than 1%) {
Err < 0.01 R= (R + m/R)/2;
*/ Err=(R*R – m)/m;
}
return R;
}
Friday, September 4, 2009 34
Module Correctness for
sqrt(x)
Termination?
Start with a range for R: x/2
Every step reduces the size of the range: average
is closer to the middle than the ends
Range should get smaller and smaller – must
terminate when R is close to the root.
Friday, September 4, 2009 35
Module Correctness for
sqrt(x)
Loop Invariant:
R <= sqrt(x) <= x/R OR x/R <= sqrt(x) <= R
Verify:
Universally true?
Side of a square vs. sides of a rectangle.
At termination, (R*R – x)/x is small (approx.)
Friday, September 4, 2009 36
Loop Invariance – Example 3
Consider the following Alg to find the index of largest integer in a list of integers
/* Pre condition: list(N) is assigned N positive integers
Post condition: list[indexMax] is a maximum element in list
*/
int maxIndex( int A[ ], int N)
{ int k, indexMax;
indexMax = 0; k=1;
while(k < N)
{
if (A[k] > A[indexMax])
indexMax = k;
k++;
}
return indexMax;
}
Correctness:
∀ j, 0 <= j < N, A[j] <= A[indexMax] and 0 <= indexMax < N
A useful invariant for the above loop:
∀j: 0 <= j < k, A[j] <= A[indexMax] and 0 <= indexMax < k
Friday, September 4, 2009 37
Loop Invariant – Example
Basis property:
When k = 1: indexMax = 0, and j=0 only
A[j] = A[0]=A[indexMax] and indexMax=0<k.
Inductive property:
Assume that the invariant is true for k = k0.
If A[k0] <= A[indexMax], then the invariant remains
true for the new k = k0+1, after executing k++
If A[k0] > A[indexMax], then after executing k++,
indexMax = k0 and A[j] <= A[indexMax], j <k0+1,
Since indexMax < k0+1, this verifies the invariant for k
= k0+1.
Friday, September 4, 2009 38
Loop Invariant – Example
Eventual falsity of Guard: simple to prove in
this case
Correctness of the Post-Condition: Falsity of
the guard and invariant implies the post
condition
(k = N) and (for all j, 0 <= j < k, A[j] <=
A[indexMax], and 0 <= indexMax < k)
Friday, September 4, 2009 39
Loop Invariance Example 4
For the algorithm to find xy, (discussed
earlier)
Write the module correctness (pre, post
conditions)
Find an appropriate invariant
Discuss the correctness argument
Friday, September 4, 2009 40
Correctness: Second Example
Algorithm for xy
Extract a power of 2 from y, say P.
Compute xP and multiply this to a temp. result
Repeat above steps until nothing to extract.
Friday, September 4, 2009 41
Correctness: Second Example
Algorithm for xy
Ynext = y; P = 1; R=1;
while (Ynext > 0) do
if (Ynext mod 2 == 1)
then R = R * pow2(x, P);
P = 2 * P;
Ynext = Ynext / 2;
endwhile;
Friday, September 4, 2009 42
Module Correctness: xy
Loop Invariant:
xy = R * x(P*Ynext)
Before the loop:
xy = 1 * x(1*y)
Inside the loop:
x(P*Ynext) = x(2*P*(Ynext/2)) if Ynext is even;
x(P*Ynext) = x(2*P*(Ynext/2))+P
= x(2*P*(Ynext./2)) * xP if Ynext is odd;
Friday, September 4, 2009 43
Module Correctness: xy
Termination:
Ynext is reduced by (at the least) half for each
iteration.
So, for positive y, Ynext will eventually be 0 –
because of integer division.
Pre-condition for Module xy:
y >= 0
Friday, September 4, 2009 44
Inter-Module Correctness
Assumption:
pow2(x,P) returns xP if P is a power of 2.
Definition of pow2
/* Pre-condition: P = 2k for some k >= 0
Post-condition: return xP */
int pow2(int x, int P)
…
Friday, September 4, 2009 45
Loop Invariance Example 5
int bsearch(int a[ ], int N, int x)
Binary Search
/* Pre condition: N>0, A is in
{
non-decreasing order int lo=0; int hi=N-1; int mid;
Post condition:
Invariant: (x is not in A) OR (A[lo] <=x<=A[hi])
(1) x = A[m] and m is the
location of the element while (lo <= hi)
OR
{
(2) x in not in A
*/ mid = (lo + hi)/2;
if (A[mid] == x) return mid;
else if (A[mid]>x) hi=mid-1;
else lo = mid+1;
}
return -1 // Not found in the given list A
}
Friday, September 4, 2009 46
Why Testing?
Verify fidelity of implementation.
Does the implementation meet design
specifications?
Verify robustness of design.
Not everything is specified in design.
Not everything about design is provably correct.
Identify and understand exceptions.
Friday, September 4, 2009 47
Testing and Design
Identification of test cases
Should be done during or before Design Phase.
High level test cases
Based on problem specification.
Low level test cases
Based on solution (design)
Friday, September 4, 2009 48
Test Case Identification [1]
E.g. Binary Search
Problem Specification:
Find the position of an element x
in an ordered list A
(of finite length, say N).
Friday, September 4, 2009 49
Binary Search Algorithm
low = 1; high = N;
while (low < =high) do
mid = (low + high) /2;
if (A[mid] = = x) return x;
else if (A[mid] < x) low = mid +1;
else high = mid – 1;
endwhile;
return Not_Found;
Friday, September 4, 2009 50
Test Case Identification [2]
What is a test case?
Any input: e.g., x = 3, A = {2, 3, 5, 7, 18}, N=5
How many test cases are there ? (for a fixed
N)
If each location of A can take k possible values, A
has kN possible values.
So, there are at least kN+1 possible values
Friday, September 4, 2009 51
Test Case Identification [3]
How many cases are enough?
Ideally all cases must be covered.
Similar cases may be grouped into classes.
e.g. x and A such that x < A{1}
Which cases are to be tested?
One sample case per class must be tested.
Friday, September 4, 2009 52
Test Case Identification [4]
Will the algorithm handle one element array?
e.g. x = 0 and A = {1}
e.g. x = 1 and A = {1}
e.g. x = 2 and A = {1}
Will it handle the case where all array values are
equal?
e.g. x = 5 and A = {5,5,5,5,5,5,5}
What if the value is the first element of the array?
- e.g. x = 5 and A = {5, 7, 9, 12}
Friday, September 4, 2009 53
Test Case Identification [5]
What if the value is the last element of the array?
- e.g. x = 12 and A = {5, 7, 9, 11, 12}
What if the value is not found in the array?
- the value is within the range:
e.g. x = 8 and A = {5, 7, 9, 12}
- the value is below the range:
e.g. x = 4 and A = {5, 7, 9, 12}
- the value is above the range:
e.g. x = 13 and A = {5, 7, 9, 12}
Friday, September 4, 2009 54
Test Case Identification [6]
All of the above questions are answerable at
design time.
Testing ensures “fidelity” of implementation.
Other questions?
Is the design complete?
Is the design proven?
Friday, September 4, 2009 55
Test Case Identification [7]
Is the solution dependent on even or odd
locations?
Needed because: (low + high)/2;
Is the solution affected by large values of low
OR high?
Suppose N=29 in LC-3. What happens when low >
28
Friday, September 4, 2009 56
Test Case Identification [8]
E.g. quad
Problem Specification:
Given a, b, and c, solve quadratic equation:
a*x2 + b*x + c = 0
Friday, September 4, 2009 57
Test Case Identification [9]
Solution:
// Pre-condition: b*b > 4*a*c
function quad(float a, float b, float c, boolean
sign) returns float
disc = b*b – 4*a*c;
if (sign) return (-b + sqrt(disc)) / (2 *a);
else return (-b – sqrt(disc)) / (2*a);
Friday, September 4, 2009 58
Test Case Identification [10]
Does the algorithm handle positive values for
a,b, and c?
Does the algorithm handle negative values
for a,b, and c?
What if a or b or c is zero?
What if all of them are zeroes?
Are calls to sqrt correct?
Friday, September 4, 2009 59
Test Case Identification [11]
Open issues in design:
Will a high value of b cause an overflow?
Will high values of a and c cause an overflow?
Will there be underflow?
b* b – 4 * a *c
(-b + sqrt(disc)) / (2*a)
Friday, September 4, 2009 60
sqrt function
/* float sqrt (float m)
Pre condition: {
m>0 float R=m/2;
Post condition: float Err= (R*R – m)/m;
R = sqrt(m) (with a relative while (Err >= 0.01)
error less than 1%) {
Err < 0.01 R= (R + m/R)/2;
*/ Err=(R*R – m)/m;
}
return R;
}
Friday, September 4, 2009 61
Test Case Identification [12]
function sqrt(float x) returns float
Will sqrt be able to handle all positive values?
Will there be any underflows?
Friday, September 4, 2009 62
Test Case Identification [13]
Exceptions
What happens when contracts are violated?
e.g. sqrt(-1)
e.g. quad(2, 1, 2, true)
- Is graceful termination guaranteed?
Friday, September 4, 2009 63
Test Case Identification [14]
Exercise:
Identify test cases for function pow2(x,y) that
computes xy when y is a power of 2.
Identify test cases for function pow(x,y) that
computes xy.
Identify exception (crash) scenarios!
Friday, September 4, 2009 64