BigInt Part II, CPS 100, Spring 1996

Due Date

Part II is due February 5 but late deadline is Feb 12 .

[ part I | part II | grading | submit | extra credit ]

Introduction

The files for Part II are the same as those used in Part I. They are accessible in ~ola/cps100/bigint on the acpub system. An itemized list of files included below (the files are accessible via the world-wide web).

You should create a directory cps100 in which all work for this class will be done (see the initial Unix/Emacs/C++ writeup). Each assignment should be done in its own subdirectory, for this assignment create a directory bigint2. All work for your assignment will then be done in the directory ~/cps100/bigint2. You should change the acl (access control list) on your cps100 directory to give the professor (and TA/UTA) permission to read your files. The command below will give Owen Astrachan (login id 'ola') read permission on the directory cps100.

   fs setacl cps100 ola read

Copy the files for this assignment into your bigint2 directory. To do this, cd into the bigint2 directory you created and type

      cp ~ola/cps100/bigint/* .
don't forget the final . (dot).


Outline

There are two parts to this assignment.

Part II (two parts)

* Reimplement Sequence using linked lists.
For this part you will re-implement the class Sequence so that it uses a linked-list (with header node) rather than a Vector. This will require that the class SeqIterator be re-implemented as well.

* Re-implement multiplication
For the second part of Part II you must re-implement multiplication of BigInt values. In the implementation you are given, multiplication is performed by repeated addition. You are to fix this so that the grade-school method of multiplying is used as outlined below

* Extra Credit
There are two sources of extra credit
* implement Sequence as a templated class
* implement subtraction of BigInt values

Subtraction is very tough, you'll need to do a fair amount of work to deal with negative numbers. You can earn partial credit if your code deals with 123 - 45, i.e., subtraction with positive results correctly.

Advice: don't use your linked-list sequence class to test your multiplication code, use the vector sequence class so that you can have high confidence that problems with the program are due to your multiplication code and not to your sequence class.


Part I: Using Linked Lists for Sequence

For this part of the assignment you will re-implement the classes Sequence and SeqIterator so that they use linked lists instead of vectors. This will require changing the header (.h) files slightly, and re-implementing the classes in the .cc files extensively. The new private section for Sequence is shown below.
  private:
    struct Node
    {
        int digit;
        Node * next;
        Node(int val, Node * ptr=0) : digit(val), next(ptr){};
    };

    int mySize;
    Node * myFirst;                  // first node in linked list
    Node * myLast;                   // last node in linked list

In implementing Sequence you should use a header node. This means that an empty sequence will consist of a single node, pointed to by both myFirst and myLast. Using a header node will simplify writing several member functions. The default constructor can then be implemented as shown below (the -1 could be any number).

   Sequence::Sequence()
   {
       mySize = 0;
       myFirst = myLast = new Node(-1);   // mark header node
   }
}

The Append and Prepend functions should be no more than three to five lines of code each. For example, to append a new digit, a node is created, myLast is updated to point to it, and mySize is incremented (but be careful, there may be special cases that require more than this!). Implementing the destructor, copy constructor, and assignment operator are trickier. For full credit, when implementing the assignment operator you should make use of nodes that already exist (e.g., part of the list being assigned to) rather than creating new nodes unnecessarily.

Linked Iterators

The private section of SequenceIterator is reproduced below.
  private:
    Sequence & mySequence;         // bound to this sequence
    Sequence::Node * myCurrent;    // internal index of current item

Note that Sequence:: must be used to qualify Node since Node is declared in the private section of Sequence. You should be careful in implementing the function Current since the pointer myCurrent may be NULL. It would be wise to check against this, and if the pointer is NULL, print an error message (to cerr) and abort the program. Be careful when using myCurrent that you remember that a header node is used in implementing the class Sequence

Testing the code

You must write a test program testseq.cc to test your linked list implementation. This program should be exhaustive, i.e., it should try appending, prepending, clearing, etc. with all kinds of lists. You should be sure to check the copy constructor and the assignment operator with your program. In your README file you should describe what you tested, and note any difficulties you encountered. Your grade for this part of the program will be largely based on how exhaustive your test suite is and on how well you document the testing in your README file. You might also check fact.cc or expo.cc with your re-implemented class, bu the testseq.cc program should be sufficient to verify that your new implementation works.

You'll need to alter the Makefile so that it has an entry for testseq.cc. The easiest way to do this is to cut-and-paste one of the entries for expo, fact, or testdiv. Be careful, the character before the $(CC) must be a TAB (when $(CC) occurs after fact:, expo:, testdiv:, etc.). To type a TAB explicitly in emacs you may need to type c-Q TAB (that's control-Q TAB).


Part II: Re-implenting *= for BigInt values

In the current implementation of the BigInt class the multiplicative assignment operator *= is implemented using repeated addition. You are to re-implement multiplication so that it is performed using a method similar to that learned in grade school. One way of doing this is outlined below.

A useful first step is to implement a function to multiply a BigInt by an int. To do this properly you will need three functions.

       BigInt & operator *= (int num);
       BigInt operator * (const BigInt & b, int num)
       BigInt operator * (int num, const BigInt & b)
The first of these does most of the work, operator * is implemented in terms of operator *=. The code is very similar to the code for adding two BigInts (see operator +=). Think about how you would multiply a 50 digit number by the integer 8 using standard ``grade-school'' methods and translate this into code. You can then add this operator to the definitions for the class BigInt in the header file bigint.h and implement it in the file bigint.cc.

Your code for multiplying a BigInt by an int only needs to work for digits 0-9. You don't need to make it work for arbitrary integers, although it's not hard to do this. However, if your code only works for digits, you'll need to test this in the function you write and pass the work of digits larger than 10 off to operator *= (BigInt & big). This is to ensure that statements like prod *= 1234 execute correctly. Since 1234 is an int, if your code only handles digits the operator *= (int) function will need to call operator *= (const BigInt &) and pass it BigInt(1234) to return the proper answer.

You'll want to test this code, the factorial function will do this since it computes the factorial of an int not a BigInt. You may want to add some diagnostic output when developing the code to assist in debugging.

Multiplying two BigInt numbers

To multiply a BigInt by a BigInt consider the example below:
1 2 3 4 5 6
x 7 8 9
----------------------------------
1 1 1 1 1 0 4
9 8 7 6 4 8 0
8 6 4 1 9 2 0 0
----------------------------------
9 7 4 0 6 7 8 4

Note that each partial product is shifted-left (padded with the appropriate number of zeros). Rather than shift the partial product by adding the appropriate number of zeros, one of the numbers being multiplied can be shifted (of course this is what is really happening in the example above where the top number is multiplied by 9, 80, and 700). This allows the product to be accumulated by summing a sequence of partial products where each partial product involves multiplying by a digit in the range 0-9. In the example above the final product is computed by

             (123,456 X 9) + (1,234,560 X 8) + (12,345,600 X 7)
Note that each partial product involves the product of a BigInt and a digit in the range 0-9. Thus the partial produces can be computed using the operator whose prototype is BigInt & operator *= (int val).

You can use the sequence function Prepend to effectively multiply by 10. You need to use Prepend since the least significant digit is stored first. You will do this when writing the operator whose prototype is below.

          BigInt & operator *= (const BigInt &);

Note that because BigInt operator *(const BigInt & a, const BigInt & b) is implemented in terms of *= you'll get good performance ``for free'' for this operator.

For full credit, you should only use Prepend once each time the loop body is executed in the implementation of *=. Read the explanation above carefully to see how this can be done.


Grading

This assignment is worth 25 points
Grading
part points
Part I linked-list
testseq.cc 5
README 4
sequence.cc 4
Part II multiplication
*= (int) 5
*= (const BigInt &) 5
README 2

Submitting

You should create a README file for this and all assignments. All README files should include your name as well as the name(s) of anyone with whom you collaborated on the assignment and the amount of time you spent. They should also include your impressions of the assignment and any writeup required by the assignment.

To submit use the command

   submit100 bigint2 README sequence.h sequence.cc seqiterator.h
             seqiterator.cc bigint.h bigint.cc Makefile testseq.cc
If you get a command not found error message, type ~ola/bin/submit100 instead of just submit100

In your README you should include the output of the expo.cc program to demonstrate your successful implementation of the *= operator for BigInt valuess. If you haven't been successful in implementing you can earn substantial credit for indicating where you think the problems lie in your code. You should use expo.cc to calculate 256^256 (or 256256 for math aware browsers), submit the result as part of your README file.


Extra Credit

templates

To create a templated class, use either the vector implementation or the linked list implementation and change the class declaration and member functions to support sequences of any type. You should include a test program that uses several kinds of sequence. Templates can be difficult to use. The easiest way of testing your template code is to #include both .h and .cc files in testtemplate.cc


// beginning of testtemplate.cc

#include "sequence.h"
#include "sequence.cc"
#include "seqiterator.h"
#include "seqiterator.cc"
This will ensure that code for each kind of template is instantiated.

Subtraction

Implement subtraction for BigInt values. This is lots of work to get completely correct because of problems like 123 - 123 (what do you do with 000?). You can earn substantial credit for subtraction taht works with results that are positive, e.g., 100 - 7 and full credit if your program deals with negative numbers, e.g, 7 - 100 (then it should deal with negative for addition and multiplication too). Grading

Templates earn 3 A/A+ points, subtraction of positives earns 6 points, and for all values earns 10 points.

Submit

Use

   submit100 bigintextra FILES