CSE 378 Homework #4
Due: Monday, 2/5/01
Assignment Goals
The goals of this assignment are to gain further experience with
assembly programming and, more specifically, procedure linkage
conventions. Also, so you don't start thinking this is just an
assembly programming course, we'll ask you to answer a few written
questions as well.
The Program
You'll be writing your old friend, quicksort - a recursive,
average-case O(NlogN) sorting routine - in assembly. In case you've
forgotten, here's the pseudo-code for quicksort, to sort an array of
integers in non-decreasing order:
void quicksort (integer A[], integer p, integer r) begin
integer q;
if p < r then
q := partition(A, p, r)
quicksort(A, p, q)
quicksort(A, q+1, r)
end if
end quicksort
integer partition (integer A[], integer p, integer q) begin
integer pivot := A[p]
integer i := p-1
integer j := q+1
while (true)
repeat j := j-1 until (A[j] <= pivot)
repeat i := i+1 until (A[i] >= pivot)
if i < j then
swap(A[i], A[j])
else
return j
end if
end loop
end partition
Your job is to write the two procedures partition and quicksort, as
well as a main. Your main should do the following:
- Prompt the user for the size of the data set to sort (non-positive
numbers should exit the program).
- Prompt the user for a seed for the random number generator.
- Generate an array full of random integers. We'll
provide a procedure which you can use to fill an array with
random numbers.
- Sort the array, by calling your quicksort procedure.
- Confirm that the sort was successful. We'll provide a procedure which
you can use to test an array for "sortedness."
- Repeat...
A sample interaction should look something like this (you must read
array size and random seed in this order so we can test your programs;
the actual prompts are up to you). User inputs are in bold:
Enter size of array to sort (max 10000; negative size to quit): 100
Enter the random seed: 23
Array sorted successfully.
Enter size of array to sort (max 10000; negative size to quit): 320
Enter the random seed: 42
Array sorted successfully.
Enter size of array to sort (max 10000; negative size to quit): -1
Bye.
What We Provide
To make your life easier, we've provided some routines for filling
an array with random numbers and checking if an array is sorted. The
specification for these functions is:
# initRandArray
# arguments: $a0 base address of array of words
# $a1 length of array (integer)
# $a2 seed for random number generator (integer)
# return val: none
# Fill in the specified number of words starting at the memory location
# given in $a0. Behavior is unspecified for non-positive size
# arrays.
# isSorted
# arguments: $a0 base address of array of words
# $a1 length of array (integer)
# return val: 1 if sorted; 0 if otherwise
# Check if given array is sorted in non-decreasing order.
# By default, arrays of length 1 are "sorted." The "sortedness" of
# non-positive length arrays is unspecified.
These routines are automatically loaded in by spim. DO NOT load
another file that has these routines. If, for your own edification,
you would like to look at the code for these routines, they can be found
in /cse/courses/cse378/CurrentQtr/lib/hw4lib.spim. DO NOT load this
file into spim.
For those of you using PCSpim at home, what we have done is insert the
code of hw4lib.spim into trap.handler, which is spim loads
automatically. This is located in the course lib/ directory,
i.e. /cse/courses/cse378/CurrentQtr/lib/. You can take a copy of
trap.handler home with you, put that in the appropriate place in your
PCSpim install, and everything should work. Note that if we update
trap.handler (with bug fixes for example), you are responsible for
updating any home copy you have. trap.handler will be more up-to-date
than hw4lib.spim. Talk to the instructor or the TA if you have any
questions or problems.
Details
Your program is responsible for allocating space for the array. It
should be able to hold at least 10000 integers. You
can make the array global, local to main, or allocate it dynamically
using one of the syscalls. Making it global is probably the easiest
method. You will be responsible for following at least the basic
calling convention we described in class. In particular, we expect
you to follow the guidelines for parameter passing (first four args in
$a0-$a3, the remainder on the stack), return value (return values are
passed via $v0), and register use (a callee may not use $s0-$s7
without saving them first, and restoring them afterwards).
We'd also like you to follow the stackpointer guidelines presented in
class.
You are writing everything from scratch (besides the routines we
provide) this time. Of course, you'd have to be nuts not to start
from some gutted version of you HW2 or HW3 solution. As always,
clarity, simplicity, efficiency (i.e., code beauty) is valued, as are
legible comments.
Quicksort and partition are not terribly complicated procedures, but
because of the recursive nature of quicksort, debugging it can be a
real pain. An hour of thinking about the design will be worth 10
hours of debugging! In all, you shouldn't find yourself
writing more than a couple pages of code (excepting comments). As
always, good design/implementation technique will make your life
easier. Start small and work incrementally towards solution (for
instance, understanding, writing, testing partition before
worrying about quicksort seems logical, but you knew that already).
We won't have much pity on the folks who use the "It's the day before
the assignment is due and I just wrote 3 pages of assembly code and
nothing works and I don't know what's wrong and I don't know where to
start debbugging and will you please help me please please ..."
approach.
Written Questions
We'd like you to answer the following questions:
- Exercises 2.10, 2.11, and 2.12 from H & P
- Exercise 3.19 from H & P
- Ask us two questions about the course.
Deliverables
We'd like an electronic and hardcopy submission of your program
file(s) as well as a harcopy submission of your answers to the written
questions, above.
This is Still Too Easy
Here are a few extra credit suggestions, in order of increasing
interest:
- Add an option which prints out the array (before and after sorting).
- For small arrays, non-recursive, O(N^2) sorting routines such as
selection/insertion/bubble-sort are actually faster than quicksort,
because they don't incur the overhead of recursive calls. Modify
quicksort so that it uses a faster method when sorting
short arrays.
- As you know, basic quicksort has a serious flaw in that it runs
in worst-case O(N^2) time, when implemented naively in the above
manner. The problem occurs when quicksort tries to sort an
already-sorted (or almost-sorted) array. The key is to do a better
job of picking a pivot. If we chose our pivot element randomly
(rather than just the first element of the array) then no particular
input can consistently elicit the worst-case behavior of the
algorithm. Furthermore, randomizing quicksort makes it highly
improbable that it will ever exhibit worst-case behavior
(because it would have to consistently choose the worst pivot).
Modify quicksort to randomly choose the pivot element.