Fall 2012, David Matuszek

- To get you comfortable with writing functions.
- To learn some string manipulation.
- To emphasize the importance of following specifications exactly.

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 "memory,", 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 function for converting to nega*ternary*, and this function can be easily adapted to one that converts to nega*decimal*.

The user will use your program by typing in negadecimal expressions such as` 500 + 692`

and will get a negadecimal number such as` 19192 `

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

We will do some **automated testing** of your assignment. That means **our program** will call functions in **your program**, and if those functions are missing, or have a different name, or different parameters, or return the wrong kind of values, then they will fail our tests. So be sure to write functions *exactly* as specified below.

Example (I am using "`Compute:`

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

are negadecimal numbers):

Compute: 3 * 5

195

Compute: dec mem

15

Compute: mem + 10

5

Compute: mem - 20

185

Compute: hello

I don't understand: hello

Compute: quit

Done.

In the descriptions below, the word integer will refer to an ordinary **integer**, such as you have already been using in Python. The term negadecimal number (ndn for short) will mean a **string** composed of one or more of the characters `'0'`

and` '1'`

.

The user may type in any of the following expressions:

`ndn + ndn`

Adds the two numbers. The result is stored in memory. `ndn - ndn`

Subtracts the second number from the first. The result is stored in memory. `ndn * ndn`

Multiplies the two numbers. The result is stored in memory. `ndn / ndn`

Divides the first number by the second. The result is stored in memory. `ndn % ndn`

Gives the remainder when dividing the first number by the second (see note). The result is stored in memory. `-ndn`

Computes the negative of the given number. The result is stored in memory. `dec ndn`

Gives the decimal value of the negadecimal number. This is the onlyexpression that returns a decimal value.Memory is unchanged.`neg decimal`

Gives the negadecimal value of the decimal number. This is the onlyexpression for which the number entered by the user is a decimal value. Moreover, the number entered may be negative.Memory is unchanged.`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,

`ndn`

may be a negadecimal number, written without quotes, or the word`mem`

. If it is the word`mem`

, then the calculator uses the number stored in its "memory" as that operand.- 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.

Save your program on a file named` negadecimal.py`

.

Here are the functions you should have.

None of the following functions should request input from the user or print anything. Except as noted, input parameters and returned results are strings representing valid negadecimal numbers.

`add(ndn_1, ndn_2)`

- Returns the sum of the two parameters. Also saves the result in memory.
`subtract(ndn_1, ndn_2)`

- Returns the difference
`ndn_1 - ndn_2`

. Also saves the result in memory. `multiply(ndn_1, ndn_2)`

- Returns the product of the two parameters. Also saves the result in memory.
`divide(ndn_1, ndn_2)`

- Returns the quotient
`ndn_1 / ndn_2`

. Does not check to make sure`ndn_2 != 0`

. Also saves the result in memory. `remainder(ndn_1, ndn_2)`

- Returns the modulus
`ndn_1 % ndn_2`

. Does not check to make sure`ndn_2 != 0`

. If negative numbers are involved, the results are the same as they would be for integers in Python (in other words, just let Python do whatever it does in this case). Also saves the result in memory. `negate(negadecimal)`

- Returns the number which, when added to
`negadecimal`

, would give zero. Also saves the result in memory. `to_decimal(ndn)`

- Returns the
**decimal integer**value represented by the**string**parameter`ndn`

. `to_negadecimal(dec)`

- Returns a
**string**representing the negadecimal value of the**integer**parameter`dec`

. `store(ndn)`

- Saves
`ndn`

in the global variable`mem`

. This function may be called by*all*of the above functions, and should be the only function that changes this global variable. `fetch()`

- Returns the negadecimal string previously saved in the global variable
`mem`

(or the string`'0'`

, if`store`

has never been called). This should be the only function that refers to this global variable. `evaluate(string)`

- 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).
- Checks for problems (illegal characters, division or mod by zero, etc.). If any problem is found, return an error message. Do not change the contents of memory (
`mem`

). - Calls one of the above methods to perform the arithmetic.
- Returns the result as a string.

Catch as many errors in the user input as you can. You probably won't be able to catch them all, unless you use features of Python that we haven't talked about. We will be testing that your methods work when given *correct* input.

`REPL()`

- This function implements a basic Read-Evaluate-Print-Loop.
It should:
__R__ead an input from the user,- This is a good place to check for
`quit`

.

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

function,__P__rint the result (either a negadecimal number, or an error message), and__L__oop (do it again). Or, instead of a loop, you could make a recursive call to`REPL`

.

This should be the**only**function that does any input/output.

- The functions
`to_decimal(negadecimal)`

and`to_negadecimal(decimal)`

are fundamental, so do these first. - Inside the program, 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 (7 lines), because most of the work is done in`evaluate(string)`

.- Rule of thumb: You should be able to see the entire function on the screen, without scrolling.

`.py`

file to Blackboard.