CMPS 144 Spring 2019
Prog. Assg. #2: Big Unsigned Integers
Due: 11:59pm, Sunday, Feb. 24

Motivation

Data TypeRange of Values
byte -27 .. 27-1
short -215 .. 215-1
int -231 .. 231-1
long -263 .. 263-1
Java, like many programming languages, has intrinsic (or what Java calls primitive) data types whose "universe of values" is a finite set. Among these are data types whose values span a range of integers. These are listed to the right.

The corresponding wrapper classes in the java.lang package (Byte, Short, Integer, and Long) all suffer from the same limitation, as an instance of any of these classes simply acts as a "wrapper" around a value of the similarly-named primitive data type.

However, some applications require calculations with integers whose magnitudes may be arbitrarily large, meaning that no particular upper bound can be known ahead of time. For applications such as these, none of the Java data types mentioned above are suitable. Which is why Java's standard library includes the class java.math.BigInteger.

Instances of BigInteger can represent integers of any magnitude, limited only by conditions imposed by the environment in which a program is running, such as how much memory is available. The class's documentation uses the phrase "arbitrary-precision integer", which refers to there being no upper bound ("arbitrary") on the number of digits ("precision") used in representing a number.


Your Task

For this assignment, you are to complete the development of the Java class BigIntUnsigned, instances of which provide a small subset of the functionality of Java's BigInteger class.

Specifically, an instance of BigIntUnsigned can represent any natural number (i.e., nonnegative integer), with no upper bound on its magnitude. (Negative numbers are not representable.) The operations supported include

Students wishing to demonstrate superior understanding are encouraged to implement not only addition and subtraction but also any or all of multiplication, integer division, and mod (i.e., remainder).

As with Java's BigInteger class, instances of BigIntUnsigned are immutable, which is to say that the class includes no mutator methods (or what your textbook authors refer to as transformer methods). Rather, the methods that implement the arithmetic operations are generators, which means that they produce a new instance of the class rather than modifying the state of any such instance. For example if x and y refer to instances of BigIntUnsigned, the method call

x.plus(y)

returns a new instance of the class representing the sum of the values represented by x and y. The states of the objects referred to by x and y are not changed.

Welcome to the BigIntUnsigned Calculator!

> 35672305934 + 67891054
Computing 35672305934 + 67891054
35740196988

> 8792345664223455 - 123456
Computing 8792345664223455 - 123456
8792345664099999

> 4569834 = 542455
Computing 4569834 = 542455
false

> 4569834 < 542455
Computing 4569834 < 542455
false

> 4569834 > 542455
Computing 4569834 > 542455
true

> 99999 * 10000000
Computing 99999 * 10000000
999990000000

> 150 / 7
Computing 150 / 7
21

> 150 % 7
Computing 150 / 7
3
For purposes of testing your work, provided is the Java application BIU_Calculator. To the right is a sample user-program dialog illustrating what it does. (Input is shown in boldface.) Essentially, it acts as a calculator: the user enters a one-operator expression; the program then echoes the expression and displays the result of evaluating it.


Implementation Suggestions

Given that you are probably more familiar with decimal numerals than with numerals of any other base, it is suggested that you design your BigIntUnsigned class to make use of a sequence of decimal digits for the purpose of representing a big unsigned integer. The two most obvious alternatives are thus to use an instance variable of type int[] or one of type ArrayList<Integer>.1. (Here is a sample program that makes use of an ArrayList.) Each choice has its advantages and disadvantages. The major advantage of using an ArrayList is that it can grow and shrink in length "automatically", while an array's length is fixed.

Whichever choice you make, it is strongly suggested that the digits be stored in a least-to-most significant order, as this will make the code implementing addition and subtraction much simpler. For example, assuming that the instance variable is named digits (whether it is an array or an ArrayList), the integer 8603472 should be stored like this:

                         0   1   2   3   4   5   6
       +---+           +---+---+---+---+---+---+---+
digits | *-+---------->| 2 | 7 | 4 | 3 | 0 | 6 | 8 |
       +---+           +---+---+---+---+---+---+---+

As for how to implement the various operators, for addition and subtraction think back to the algorithms that you learned in elementary school. Both involve iterating through the digits of the two operands, going from least significant digit to most significant. Addition involves a "carry" from one column to the next, while subtraction involves "borrowing" from the next column.

If you are attempting to implement the multiplicative operators (multiplication, division, remainder), you are encouraged to make use of this characterization of multiplication:

k * m = { 0   if k = 0
k/2 * 2m   if k>0 and k is even
((k-1)/2 * 2m) + m   if k>0 and k is odd

To support taking this approach, you will probably want to develop private methods for doubling and for halving an instance of BigIntUnsigned.


Program Submission

Use the file submission system (see the link near the top of the course web page) to submit your completed BigIntUnsigned.java file into the prog2_dir folder. Make sure to complete the comments indicated near the top of the source code that has been provided. In particular, you should put your name and list the names of anyone who aided/collaborated with you in doing the work. Also, you are to describe any behavioral defects that your class has (e.g., characterizations of test cases that it fails). If there are defects of which you are unaware, it probably means that you did a poor job of testing your work. Thus, of two submissions having similar defects, one in which those defects are acknowledged deserves a better grade than one in which they are not acknowledged.


Footnotes

[1] To make objects of BigIntUnsigned more memory-efficient, you could use an instance variable of type byte[] or ArrayList<Byte> instead, but that would make doing arithmetic a little less convenient. Why? Because Java's arithmetic operators (+, -, etc.) produce values of type int even when the operands are of type, say, byte. To store the result as a value of type byte, it is necessary to perform a cast, as in (byte)(k+m).

It would also be reasonable to use an instance variable of type char[] or ArrayList<Character>.