CS 1501

Data Structures and Algorithms

Programming Project 1

 

The purpose of this assignment is to empirically compare a production very-long-integer multiplication algorithm such as that in the NTL library with one that you write yourself. You will time both algorithms for various integer sizes (i.e. numbers of bits/digits) and see how the run-times compare.

 

The ZZ multiplication algorithm from the NTL library is a hybrid algorithm – it uses the Gradeschool algorithm ("classical" algorithm as described in NTL) until a certain integer size, and then crosses over to the Karatsuba algorithm.  Some details about how integers are stored and manipulated in the NTL library can be found at this link.  For better space (and perhaps time) efficiency, NTL ZZ values are stored and manipulated in binary form.

 

As we discussed in class, we could alternatively store very-long-integers (VLIs) as arrays of digits, with each array location corresponding to a single base-ten digit of the number (we will assume no negative numbers are allowed). The advantage of this method is easier understanding and manipulation by the programmer, with the cost being more space (and perhaps more time).

 

Your assignment consists of two parts:

1)      Implement your own VLI class in C++, including all of the operations that the integers would need.  Minimally these operations should include:

·         A constructor that takes a character string of digits and produces a VLI from it

·         Various other constructors, destructors and assignment operators as necessary (your data must be stored in some type of dynamic array, sized to the exact number of digits of the integer)

·         Overloaded input and output operators (>> and <<)

·         Addition operator (+)

·         Multiplication (*) using the Gradeschool algorithm

To demonstrate that your VLI class works properly, you MUST write a simple driver program that tests each of the operations for your class.  The TA should be able to execute this program to see that each of your operations is correct.  Call this program assig1a.cpp.

2)      Time your multiplication algorithms with both ZZ integers and your VLIs in the following way:

·         Generate random strings of digits (as characters) and for each string generate both a ZZ and a VLI using the appropriate constructors/conversion functions (i.e. you should use the SAME VALUES for both algorithms). You should generate strings with the following numbers of decimal digits: 20, 40, 80, 160, 320, … continuing until it takes at least 1 minute to do the multiplication (as timed below) for the algorithm in question.

·         Time both of your multiplication algorithms for each of the random integers as described below:

1)         Generate the next pair of random values (one for each operand)

2)         Start the system clock

3)         Execute the multiplication algorithm

4)         Stop the system clock

5)         Calculate the elapsed time

6)         If the number of digits is <= 40, output the answer (the product) calculated by the algorithm in a clearly labeled way (this is for grading correctness of your multiplication algorithm – the answer produced by the NTL multiplication and by your VLI multiplication should be the same)

·         The timing will differ depending on which C++ environment you use.  See documentation for your environment to help you with the timing.

·         Store/save the (digits, elapsed time) pairs for both of the multiplication algorithms for each digit value used (remember that the max value for digits may be different for different algorithms).  For the smaller numbers of digits, you may get results of 0 -- this is ok as long as you eventually get significant values for the larger numbers of digits.

·         Run your program 10 times and average the results for each algorithm.

·         Call this program assig1b.cpp.

 

BE SURE TO DO ALL OF YOUR RUNS on the SAME COMPUTER under the SAME CIRCUMSTANCES.  Timing on Windows NT machines may not be very accurate but if you try to have the same conditions for all runs the relative times will still be somewhat meaningful.  Also, DO NOT do anything in the background while your program is running -- this will affect your results!

 

Clearly, an important part of this assignment is installing/figuring out how to use the NTL Library. If you do not have a PC, and do not want to try using Unix, I suggest buying a ZIP disk and installing the library onto the ZIP disk (many campus computing labs have ZIP drives).  Then you can take your library with you to any campus PC that has a ZIP drive.

 

The Gradeschool algorithm that you will use in your VLI class is not exactly the way you learned it in gradeschool.  If we had to calculate each of the partial products and store it before adding, it would waste too much memory (Theta(D2) memory would be needed, where D is the number of decimal digits).  Instead we can add while we are multiplying if we calculate the answer in a column-wise rather than a row-wise fashion.  The pseudo-code below should show how this is done.

 

function Mult (X[0..n-1], Y[0..n-1]) returns Z[0..2n-1]

               // note: X and Y have n digits Z has UP TO (2n) digits

               // The LEAST significant digits (smaller powers of ten)

               // stored in the smaller indices

          long  S = 0

          for  j  from  0  to  (2n-1)  do      // go through digits of result

                  for  i  from  0  to  (n-1)  do    // digits of X

                          if  (0 <= (j-i) <= (n-1))  then

                               S = S + X[i] * Y[j-i]

                  Z[j]  =  S  mod  10   // remainder

                  S  =  S / 10          // integer division

          return  Z

end function

 

Be careful when implementing this algorithm.  Try a few simple examples with a pencil and paper before coding it.  Also make sure you don't violate any of the array bounds.  Since the final length of Z is not certain until the multiplication is complete, you can define a temporary array of length 2n to store the result, then create an exact length VLI to return when finished.  Remember that it is VITALLY IMPORTANT that your VLI class functions correctly in all aspects.  If your VLI class does NOT work correctly (and, in particular, does not produce the correct answer to the multiplication) you will lose much of the credit for it.

 

Once you have completed your algorithm runs, compile a table of your averaged results and make a graph for each of the algorithms.  Use the digits (n value) as your x-coordinate and the average run-time as your y-coordinate.

 

Important Submission Note:  You must submit 2 programs for this assignment, one that demonstrates your VLI class and one that does the simulation/timing for the comparison results.  For EACH of these programs, you MUST submit both your SOURCE code AND your EXECUTABLE code on a disk (or in an AFS directory if you did it using g++).  The executables that you submit MUST EXECUTE INDEPENDENT of any software you used or PC configuration used to develop them.  In other words, the TA should be able to put your disk into ANY WIN32 machine and your programs should execute correctly.  If you have ANY DOUBT about this with your programs, TEST your executables on various, differently configured PCs BEFORE handing them in.

 

Write a short (~ 2 double-space (NOT HAND-WRITTEN) pages) paper discussing your program and results thoroughly.  Be SURE to address the following questions: 

·         Program: How did you set up your main program? Which functions in NTL did you utilize in addition to the multiplication and why? How did you do your timing? What (if any) obstacles did you have to overcome?  Did all 10 runs give similar results?  If not, speculate as to why not.

·         Results: Which of the algorithms was faster and why?  Did the difference in the run-times seem to be a constant factor throughout all of the numbers of digits?  Speculate as to why or why not.  What could you have done to improve the run-time of your algorithm?  From your results does it seem that the added complexity of the NTL code is worth it?

 

(Difficult) Extra Credit Idea:  Also implement the Karatsuba algorithm for your VLI class and test it along with the Gradeschool algorithm.