Fall 2014, David Matuszek

- To get you started programming in Java.
- To introduce the use of more than one class.
- To learn some string manipulation.
- To familiarize you with JUnit testing in Java.

Note: This is probably the most abstract (and least practical) assignment you will get this semester.

Your assignment is to write a "calculator" for negadecimal integers. It will be able to do addition, subtraction, multiplication, and integer division, as well as negation and modulus (remainder). It will also have a one-number "display,", and it will be able to convert between decimal and negadecimal.

Negadecimal is a place notation like decimal, only instead of powers of 10, the notation uses powers of -10: 1, -10, 100, -1000, 10000, -100000, etc. For example,

The number: | 7 | 1 | 0 | 2 | 5 | ||||||
---|---|---|---|---|---|---|---|---|---|---|---|

In decimal, means: | 7*10000 | 1*1000 | 0*100 | 2*10 | 5*1 | ||||||

In negadecimal, means: | 7*10000 | 1*-1000 | 0*100 | 2*-10 | 5*1 |

So, while 71025 is our usual decimal notation for 71025_{10} , the negadecimal number 71025_{-10} , translated to decimal, would be 68985.

An interesting characteristic of negadecimal is that numbers with an even number of digits are negative, while numbers with an odd number of digits are nonnegative (zero or positive).

It is easy to translate **from** negadecimal to decimal:

5 times 1 is 5 2 times -10 is -20 0 times 100 is 0 1 times -1000 is -1000 7 times 10000 is 70000 5 - 20 + 0 - 1000 + 70000 = 68985 |

However, converting **to** negadecimal is more complicated. Fortunately, the Wikipedia article linked to above gives a C++ method for converting to nega*ternary*, and this method can be easily adapted to one that converts to nega*decimal*. (Important: *Don't* try to use the Python version; the `%`

operator gives different results for negative numbers.)

The user will use your program by typing in negadecimal expressions that modify the display. For example, if the display holds` 500`

and the user types in `+692`

, the calculator will compute `500+692`

and display as` 19192 `

as a result. Details of what the user may type are given below.

You should do unit testing of all your methods that don't do I/O, and we will also unit test your program. As you know, that means that our tests must be able to call your methods, so you should be extremely careful to write functions *exactly* as specified below.

Each instance (object) of this class will represent one negadecimal number. That negadecimal number will be retained in an instance variable of type `int`

.

The `NegadecimalNumber`

class will have two constructors:

`public NegadecimalNumber(String s)`

- This constructor expects a string representation of a negadecimal number, which it converts to a (decimal)
`int`

and stores in an instance variable. However, if the string does not consist entirely of digits, or is an empty string, an`IllegalArgumentException`

should be thrown. `public NegadecimalNumber(int n)`

- Saves the integer (decimal) parameter in an instance variable.

In addition, the `NegadecimalNumber`

class has a number of methods for maniuplating negadecimal numbers, and for combining them with other negadecimal numbers:

`public NegadecimalNumber add(NegadecimalNumber ndn)`

- Returns a new negadecimal number which is the result of adding
`ndn`

to "this" negadecimal number. `public NegadecimalNumber subtract(NegadecimalNumber ndn)`

- Returns a new negadecimal number which is the result of subtracting
`ndn`

from "this" negadecimal number. `public NegadecimalNumber multiply(NegadecimalNumber ndn)`

- Returns a new negadecimal number which is the result of multiplying
`ndn`

and "this" negadecimal number. `public NegadecimalNumber divide(NegadecimalNumber ndn)`

- Returns a new negadecimal number which is the result of dividing "this" negadecimal number by
`ndn`

. Throws an`ArithmeticException`

if`ndn`

is zero. `public NegadecimalNumber remainder(NegadecimalNumber ndn)`

- Returns a new negadecimal number which is the remainder after dividing "this" negadecimal number by
`ndn`

. Throws an`ArithmeticException`

if`ndn`

is zero. `public NegadecimalNumber negate()`

- Returns a new negadecimal number which which, when added to
`negadecimal`

, would give zero. `public int decimalValue()`

- Returns the decimal equivalent of this negadecimal number.
`public boolean equals(NegadecimalNumber ndn)`

- Returns
`true`

if this number andhave the same value. Necessary for unit testing.`ndn`

`public String toString()`

- Returns the string representation of this negadecimal number.

This class contains a `main`

method. When executed, this method acts as a simple calculator, using the negadecimal number system. The calculator's "display" shows the (negadecimal) number currently in the calculator (`0`

when the program first starts up. Subsequent operations use this number and, in the case of a binary operation, the number entered by the user, to compute a new number to display.

In the descriptions below, the word integer will refer to an ordinary `int`

value. The term negadecimal number (ndn for short) will mean a **string** composed of decimal digits *only*.

The user may type in any of the following expressions. After entering an expression, the calculator performs the requested operation and displays the result. If the user enters an illegal number (a blank line, or something not composed entirely of digits), the word `Error`

will be displayed instead.

`ndn`

Replaces the number currently in the display with this new number .`ndn`

`+ ndn`

Adds `ndn`

to the current display.`- ndn`

Subtracts `ndn`

from the current display.`* ndn`

Multiplies the current display by `ndn`

.`/ ndn`

Divides the current display by `ndn`

. Displays`Error`

if`ndn`

is zero.`% ndn`

Gives the remainder when dividing the display by `ndn`

.`~`

Computes the negative the display, that is, zero minus the number in the display. `?`

Showsthe decimal value of the displayed negadecimal number, thenredisplaysthe negadecimal number. This is a way of "peeking" at the decimal value of a number without modifying the current value in the calculator.`decimal integer`

Replaces the number currently in display with the negadecimal equivalent of the decimal number entered by the user. This is the onlyexpression for which the number entered by the user is a decimal value.`clear`

Clears any errors and replaces whatever is in the display with 0. `quit`

Quits the program.

Your "calculator" will remember the last number computed (initially zero, when you start the program). In each of the above expressions,

- The user may (or may not) put spaces before or after numbers, and before or after operators.
- The user may enter leading zeros (such as
`00191`

); however, your calculator should not give results with leading zeros. - If at any time the calculator displays
`Error`

, the user must enter`c`

("clear") before anything else can be done. - The commands
`decimal`

,`clear`

, and`quit`

can each be abbreviated to a single letter.

The Negadecimal calculator should have (at least) the following methods:

`public String evaluate(String s )`

- Takes a string that may have been entered by the user (or may have come from our test methods), and
- Finds the various parts of the string (for example, first operand, operator, second operand).
- Tries to parse the input, that is, recognize what kind of command it is. If the input does not appear to be a legal command, return an error message (possibly just "Error").
- Calls one of the above methods to perform the arithmetic.
- Returns the result as a string.

`public void REPL()`

- This method implements a basic Read-Evaluate-Print-Loop.
It should:
ead an input from the user,**R**- This is a good place to check for
`q`

(quit).

- This is a good place to check for
valuate it, using the above**E**`evaluate`

function,rint the result (either a negadecimal number, or an error message), and**P**oop (do it again). Or, instead of a loop, you could make a recursive call to**L**`REPL`

.

This should be the**only**function that does any input/output. `public static void main(String[] args)`

- This is the method that begins the program. All it should do is create an instance of
`NegadecimalCalculator`

and call its`REPL`

method.

Example (I am using "`Compute:`

" as a prompt; all numbers *except* the response to `?`

are negadecimal numbers):

Compute: 195

195

Compute: ?

195 (decimal 15)

Compute: +10

5

Compute: - 20

185

Compute: hello

Error

Compute: c

0

Compute: quit

Done.

- Inside the
`NegadecimalNumber`

class, you can do the arithmetic using integers. Why try to multiply two strings? - It's better to have many short functions than a few long ones. My
`REPL`

function is very short, because most of the work is done in`evaluate(string)`

. - Rule of thumb: You should be able to see each complete function on the screen, without scrolling.
- Characters in Java
*are*numbers, and you can do arithmetic on them; this will give you an`int`

result. - You can "index" into a String with the
`charAt(i)`

method. For example,`s.charAt(0)`

will return the first character in string`s`

. - The most critical things to write first are the constructors, and the methods
`toString`

and`equals`

. - You can test if a character
is a digit by calling the method`ch`

`Character.isDigit(`

.*ch*) - You can throw an exception by saying
`throw new`

, where*TypeOfException*();

is, for example,*TypeOfException*`IllegalArgumentException`

. - You can catch an exception by saying
`try {`

*code that might throw an exception of type TypeOfException*} catch (*TypeOfException*e) {*what to do now that you've caught it*}

Let Eclipse do most of the work for you!

After you have stubs for all your methods in a class, make sure the class is selected, then go to `File → New → JUnit Test Case`

. Make sure "New JUnit 4 test" and "setUp()" are selected. *Don't* click `Finish`

! Click `Next>`

and select the methods you want unit tests for. *Then* you can click `Finish`

.

All of the methods are set up to call `fail("Not yet implemented")`

. Replace these calls with more meaningful calls. The most commonly used methods are:

`assertEquals(`

*expected_result*,*call_of_method*)`assertTrue(`

*call_of_method*)`assertFalse(`

*call_of_method*)

For method calls that you expect to throw an assertion, you need to modify the `@Test`

annotation to read

`@Test(expected=`

*TypeOfException*.class)

and inside the test method, you don't need to call any "assert" methods, just call the method you want to throw an exception.