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:
  1. Prompt the user for the size of the data set to sort (non-positive numbers should exit the program).
  2. Prompt the user for a seed for the random number generator.
  3. Generate an array full of random integers. We'll provide a procedure which you can use to fill an array with random numbers.
  4. Sort the array, by calling your quicksort procedure.
  5. Confirm that the sort was successful. We'll provide a procedure which you can use to test an array for "sortedness."
  6. 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:
  1. Exercises 2.10, 2.11, and 2.12 from H & P
  2. Exercise 3.19 from H & P
  3. 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:
  1. Add an option which prints out the array (before and after sorting).
  2. 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.
  3. 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.

dugan@cs.washington.edu