UI is hell: four-function calculators

jandeboevrie1 pts0 comments

UI is hell: four-function calculators - lcamtuf’s thing

lcamtuf’s thing

SubscribeSign in

UI is hell: four-function calculators<br>One of the simplest and best-known computing devices on the planet is a fascinating study in interface design.<br>Jan 23, 2025

49

12

Share

I have a thing for the history of calculators; they were among the earliest portable electronics, they pushed the limits of display technologies, and were the first digital computing devices to enter millions of homes.

A generic, basic LCD calculator. Photo by author.<br>Today, if you asked any self-respecting software engineer to implement a simple but backward-compatible button-operated calculator, they would probably roll their eyes and say they can get it done on a single lunch break. They would fail. I know because a while back, I built a calculator of my own design — and it’s been a ride.<br>Let’s start with the basics: the simplest calculator has ten digit keys, a decimal dot, four arithmetic operators (+, -, ×, ÷), a result button (“=”), and a “C” key to reset state. It executes two-operand arithmetics sequentially, with no attention to precedence — e.g.:<br>\(\require{color}<br>\begin{array}{l l l l l l l l}<br>① & + & ② & × & ③ & = & \textcolor{steelblue}{\fbox{_____9}} & ((1+2)×3) \\<br>\end{array}\)

We can easily imagine implementing this behavior with three variables: an input register, an accumulator, and an operator selector. The entry of every new digit shifts the contents of the input register one decimal place to the right. Selecting an operator loads this value into the accumulator and makes room for the second operand to be typed in. Finally, the user presses “=”; at that point, the result is computed and the value is put back in the input register, making it available for any subsequent ops:<br>\(\begin{array}{|l|l|l|}<br>\hline<br>\textbf{Keypress} & \textbf{Input register} &<br>\textbf{Accumulator} & \textbf{Op select} \\<br>\hline<br>\textrm{C} & \color{steelblue}{clear} & \color{steelblue}{clear} & \color{steelblue}{clear} \\<br>① & \color{crimson}{1} & 0 & \\<br>② & \color{crimson}{12} & 0 & \\<br>+ & \color{steelblue}{clear} & \color{crimson}{12} \ (load) & \color{crimson}{+} \\<br>③ & \color{crimson}{3} & 12 & + \\<br>= & \color{crimson}{15} & \color{steelblue}{clear} & \color{steelblue}{clear} \\<br>\hline<br>\end{array}\)

But then… what happens if the user presses ⑨ right after the equals sign? The result probably shouldn’t be “159”. We need a special case: if a digit or a decimal dot is pressed immediately after some non-numerical input, the input register should be cleared. We can fix that with an additional “input reset” flag:<br>\(\begin{array}{|l|l|l|}<br>\hline<br>\textbf{Keypress} & \textbf{Input register} &<br>\textbf{Accumulator} & \textbf{Flags} \\<br>\hline<br>\textrm{C} & \color{steelblue}{clear} & \color{steelblue}{clear} & \color{steelblue}{clear} \\<br>① & \color{crimson}{1} & 0 & \\<br>② & \color{crimson}{12} & 0 & \\<br>+ & 12 & \color{crimson}{12} \ (load) & \color{crimson}{+, InR} \\<br>③ & \color{crimson}{3} & 12 & \color{crimson}{+} \\<br>= & \color{crimson}{15} & \color{steelblue}{clear} &<br>\color{crimson}{InR} \\<br>⑨ & \color{crimson}{9} & 0 & \color{steelblue}{clear} \\<br>\hline<br>\end{array}\)

The added perk of the revised scheme is that we can keep the previously-entered operand on the screen for a bit longer in step 4, so data entry errors are easier to spot.<br>Done and dusted, right?<br>Well… but what if the user enters ② + ③ × ⑤ =? In the aforementioned scheme, we’d end up discarding the first addition and just executing ③ × ⑤ =. To address this problem, we need another special case: if an operation is already selected, we should implicitly press “=” before scheduling another one.<br>And what if the user enters ② × ÷ ③? They probably didn’t mean 2 × 2 ÷ 3! The most logical explanation is that they fat-fingered the operator and are trying to correct their mistake. So, we need another special case: that implicit “=” should trigger only if some numeric input happened in between — i.e., when the InR flag isn’t set.<br>But does the same explanation hold for ② × - ③? Is that an attempt at subtraction, or is the user trying to multiply by a negative number? Your guess is as good as mine; either way, the ability to specify negative numbers would be nice to have. Some calculators worked around the ambiguity by having a dedicated sign button; many didn’t, instead offering a special-cased unary suffix notation right before “=”:<br>\(\begin{array}{l l l l l l c r}<br>① & ⓪ & × & ② & + & = & \textcolor{steelblue}{\rightarrow} \ & 20 \\<br>① & ⓪ & × & ② & - & = & \textcolor{steelblue}{\rightarrow} \ & -20<br>\end{array}\)

The unary operator is a clever hack, but it leads to more UX confusion down the line. For one, it usually changes the sign of the entire expression, not just the preceding operand. For addition or subtraction, this produces mildly counterintuitive results:<br>\(\begin{array}{l l l l l l c r l}<br>① & ⓪ & + & ② & - & = & \textcolor{steelblue}{\rightarrow} \ & -12 & (-(10+2))<br>\end{array}\)

Some...

color steelblue crimson clear array input

Related Articles