Approximate overview
Why did you point out the strange output in a student’s HW6?
Here’s what the student submitted as times.
round,size,insertion,rms,bucket-sort-1,bucket-sort-2,radix-sort,mysort
r000,2000,8615,311,320,3066,5433,271
r001,2000,7477,299,290,5360,2662,118
r002,2000,9162,342,286,3678,20936,175
r003,2000,15612,7212,391,12442,3816,202
r004,2000,24189,337,368,5816,4448,206
r005,2000,10127,353,336,16125,7496,219
r006,2000,20656,364,373,7828,4612,196
r007,2000,15277,1258,4806,10338,34602,353
r008,2000,22096,41912,14551,6007,3430,186
r009,2000,11505,333,329,7208,5642,119
When you see data like this, you should be asking “why”?
Form hypotheses: (1) There are some inputs for which these procedures are really slow. (2) My CPU was spending time on other processes for a bit, which slowed things down. (3) There is a ghost in my computer that doesn’t like me. (4) Allocating 10GB with repeated calls to
malloc(1)is not a good idea.:w
Graphing helps us form hypotheses.
Perhaps gather more data. Maybe run 100 trials rather than 10. Maybe gather the input data (in a file) and re-run to see if you get similar times.
This unit is “Program Verification and Loop Invariants”
x = 5, x is positive, x > y{ }
x := 5;
{ x = 5 }
{ y < 6 }
x := 5
{ x = 5, y < 6 }
x{ x > y }
x := 5;
{ x = 5 }
{ S1 }
if (TEST) then
{ S1, TEST holds }
CONSEQUENT;
{ S2 }
else
{ S1, TEST does not hold }
ALTERNATE;
{ S3 }
fi
{ S2 or S3 } OR { S2 intersect S3 }
Side note: You try to ensure that that intersection is non-empty and useful.
{ vals contains one copy each of 6, 1, 3, 2, 5 }
sort(vals);
{ vals is sorted and vals contains one copy each of 6, 1, 3, 2, 5 }
{ combined: vals is [1, 2, 3, 5, 6] }
{ S1 }
while (TEST) do
{ S1, TEST }
BODY
{ S2 }
done
{ !TEST and not much else }
So, we often try to write
{ S1 }
while (TEST) do
{ S1, TEST }
BODY
{ S1 }
done
{ !TEST and S1 }
Here’s an example where the same S1 represents an increase in knowledge
{ A is sorted in positions 0 through i }
while (i < n) do
{ A is sorted in positions 0 through i, i < n }
BODY
i += 1
{ A is sorted in positions 0 through i }
done
{ A is sorted in positions 0 through i and i = n }
{ A is sorted in positions 0 through n }
We’ve “proven” that our sorting algorithm is correct, provided it keeps S1 true at the end of each loop.
Ideally, we should be able to
// { x = 5 }
printf ("%d\n", x); // 5
// { x = 5 }
foo(y);
// { postconditions of y; ??? }
printf ("%d\n", x); // 6
Why might this have happened?
x may be a global variable that gets referenced in fooy may be a pointer to x. e.g., void foo(int *y) { *y = 6; }int *z = &x; ...; void foo(int y) { *z = y; }Most of the time, we’ll pretend we’re working in a language where none of this happens. Good programming strategies (e.g., no globals, care with pointers) helps.
Write an iterative binary search in C. You may not do Sam-like things, such as adding to pointers. No helper procedures!
/**
* Return an index of val in vals. If val does not
* appear in vals, returns -1.
*
* @pre: vals is sorted in non-decreasing order.
*/
int
binary_search (int val, int vals[], int n)
{
} // binary_search
See examples/binary-search for the Makefile and test code.
Please record your first set of results (inputs you got wrong, how many tests you failed, whether it ran forever).
You can then revise as you consider appropriate.
mid = (lb + ub)/2;lb + (ub-lb)/2;Idea: We look for states for which
These are “loop invariants”.
I0: If val is in the array, then it’s in the subarray [lb..ub).
{ I0 }
while (lb < ub)
{ I0 and (lb < ub) }
CODE
{ I0 }
end while
{ I0 and (lb >= ub) }
{ Whoops! It's not in the array. }
Problems: (a) Maintaining the invariant (I0) and (b) ensuring that the loop terminates.
Stay tuned for the next class.
What if, instead of any index, we want the first index? (And we want the search to remain O(logn).)