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 7102510 , 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 negaternary, and this method can be easily adapted to one that converts to negadecimal. (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)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)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)ndn to "this" negadecimal number. public NegadecimalNumber subtract(NegadecimalNumber ndn)ndn from "this" negadecimal number. public NegadecimalNumber multiply(NegadecimalNumber ndn)ndn and "this" negadecimal number. public NegadecimalNumber divide(NegadecimalNumber ndn)ndn. Throws an ArithmeticException if ndn is zero. public NegadecimalNumber remainder(NegadecimalNumber ndn)ndn. Throws an ArithmeticException if ndn is zero. public NegadecimalNumber negate()negadecimal, would give zero. public int decimalValue()public boolean equals(NegadecimalNumber ndn)true if this number and ndn have the same value. Necessary for unit testing. public String toString()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.
ndnReplaces the number currently in the display with this new number ndn.+ ndnAdds ndnto the current display.- ndnSubtracts ndnfrom the current display.* ndnMultiplies the current display by ndn./ ndnDivides the current display by ndn. DisplaysErrorifndnis zero.% ndnGives the remainder when dividing the display by ndn.~Computes the negative the display, that is, zero minus the number in the display. ?Shows the decimal value of the displayed negadecimal number, then redisplays the negadecimal number. This is a way of "peeking" at the decimal value of a number without modifying the current value in the calculator. decimal integerReplaces the number currently in display with the negadecimal equivalent of the decimal number entered by the user. This is the only expression for which the number entered by the user is a decimal value. clearClears any errors and replaces whatever is in the display with 0. quitQuits the program.
Your "calculator" will remember the last number computed (initially zero, when you start the program). In each of the above expressions,
00191); however, your calculator should not give results with leading zeros.Error, the user must enter c ("clear") before anything else can be done. 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 )public void REPL()q (quit).evaluate function, REPL.public static void main(String[] args)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.
NegadecimalNumber class, you can do the arithmetic using integers. Why try to multiply two strings?REPL function is very short, because most of the work is done in evaluate(string). int result. charAt(i) method. For example, s.charAt(0) will return the first character in string s. toString and equals. ch is a digit by calling the method Character.isDigit(ch).throw newTypeOfException();, whereTypeOfExceptionis, for example, IllegalArgumentException.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.