CIT 591 Assignment 7: Calculator Specifications
Fall 2004, David Matuszek

As I said from the beginning, your Fraction/Complex calculator should behave like a cheap four- or five-function calculator.

Even a cheap calculator has some surprisingly sophisticated behavior. It's trickier than you might think to make a calculator behave in a simple, obvious fashion. Like many things in computer science, it is easy to make things complicated, but difficult to make things simple.

Here are some of the things that I expect:

One operation at a time

In Java, and on sophisticated calculators, 2+3*4 equals 14, because multiplication has higher precedence than addition, so 2+3*4 = 2+(3*4). This requires that once you get an operation and both operands, you still have to wait to get the next operator, compare precedences, and maybe get the next operand, before you can do anything. This is hard to keep track of.

Much simpler, and what I would like to see, is that you perform each operation as soon as you have the necessary operands. Thus, as soon as you get 2+3 you would do the addition and get 5; then you would get *4 and compute 5*4, giving 20; effectively, (2+3)*4.

Display always up to date

Whenever you type a numeric key, that digit should appear on the screen. As soon as you perform an operation, that result should appear on the screen. When you begin typing a number, that number should replace what is on the screen.

Key typed:
5
*
1
0
+
1
4
/
2
=
Display:
5
5
1
10
50
1
4
64
2
32

A slightly nicer display might be to also show (1) the pending operation, or (2) both the preceding operand and the pending operand. For example:

Key typed:
5
*
1
0
+
1
4
/
2
=
Alt. Display 1:
5
*
* 1
* 10
+
+ 1
+ 14
/
/ 2
32
Alt. Display 2:
5
5*
5*1
5*10
50+
50+1
50+14
64/
64/2
32

But that's completely optional. It looks nice, but simple calculators don't do this, and you don't have to, either.

Since you aren't dealing with simple integers, there is another complication: Some keys might be part of the number (/ for fractions, + and - for complex numbers). Here's how I recommend that you handle this:

For fractions: If a slash can be part of the number, then it should be part of the number. So 3/4/1/2 would mean 3/4 divided by 1/2.

Key typed:
3
/
4
/
1
/
2
=
Alt. Display 1:
3
3/
3/4
3/4
1
1/
1/2
3/2
Alt. Display 2:
3
3/
3/4
3/4 /
3/4 / 1
3/4 / 1/
3/4 / 1/2
3/2

For complex numbers: If a plus or minus can be part of the number, then it should be part of the number, until proven otherwise. If a number ends by hitting the i key, then that confirms it is imaginary; but if it ends by hitting some other non-numeric key, it is real. Hence:

Key typed:
2
+
3
+
4
+
5
i
Display:
2
2+
2+3
5+
5+4
9+
9+5
9+5i

In the above, 3 is considered to be (probably) the imaginary part of the complex number, until the following + is type. At that point, since the 3 didn't end in i, it must be real, hence it is just added to the 2. Then the second + again may be part of the complex number, so it is kept.

In the above, every key typed could have been, at the time it was typed, part of the complex number, so everything above should be displayed.

Key typed:
1
+
3
i
+
3
-
1
i
/
2
=
Display:
1
1+
1+3
1+3i
1+3i
3
3-
3-1
4+2i
4+2i
2
2+1i
Alt. Display 1:
1
1+
1+3
1+3i
+
+ 3
+ 3-
+ 3-1
4+2i
/
/ 2
2+1i
Alt. Display 2:
1
1+
1+3
1+3i
1+3i +
1+3i + 3
1+3i + 3-
1+3i + 3-1
4+2i
4+2i /
4+2i / 2
2+1i

Again, only the simplest display is fine. I don't think the longer (and nicer) displays would be much extra work, but in any case, they are not required.

Don't require unnecessary key presses

If the user types 12*34*56=, there is no reason to require any extra keys, such as 12*34=*56= or 12*34[enter]*56=. As soon as the user hits the second *, you know that the second operand is complete, so do the pending operation right away. In fact, each time you hit an operator key, such as *, you can pretend that the user hit = then *. This should be easy; all you should need to do is call the method that processes the = key.

It is a good idea to keep the Listeners for your buttons as short as possible. Typically, they should do nothing more than call an appropriate method. By separating the GUI Listener code from the code that does the actual work, you can greatly simplify the cost of making changes to your program. For example, if all the code for handling the = button is in the listener for that button, then it can't really be called from anyplace else. If it's in a method, then you can call it easily.