DEV Community

Michael Lip
Michael Lip

Posted on • Originally published at zovo.one

The Order of Operations Bug That Plagues Every Online Calculator

Type 2 + 3 * 4 into a calculator. If it returns 14, it understands order of operations (PEMDAS/BODMAS). If it returns 20, it's evaluating left-to-right. You'd be surprised how many online calculators get this wrong.

The parsing problem

Building a calculator that handles 2 + 3 * 4 = 14 requires an expression parser that understands operator precedence. The naive approach, evaluating left-to-right as the user types, gives the wrong answer.

The correct approach uses one of two algorithms:

Shunting-yard algorithm (Dijkstra, 1961): Converts infix notation (the way humans write expressions) to reverse Polish notation (RPN), which can be evaluated on a stack without worrying about precedence. The algorithm uses an operator stack to handle precedence and associativity.

Recursive descent parser: Builds a parse tree where higher-precedence operators are deeper in the tree. Evaluating the tree bottom-up naturally gives the correct precedence.

The shunting-yard algorithm is more common in calculator implementations because it's iterative and maps well to the character-by-character input model.

Implicit multiplication

Mathematicians write 2(3+4) to mean 2*(3+4). Most online calculators don't handle this because the parser expects an explicit operator between the 2 and (. Similarly, sin(x)cos(x) means sin(x)*cos(x), but the parser sees two function calls with no operator.

Handling implicit multiplication requires the tokenizer to insert multiplication tokens when it encounters: digit-followed-by-open-paren, close-paren-followed-by-digit, close-paren-followed-by-open-paren, or digit-followed-by-function-name.

Negative numbers vs subtraction

Is -3^2 equal to 9 or -9? Mathematically, it's -9 because exponentiation has higher precedence than negation. But many calculators interpret the - as part of the number literal (-3) and return 9.

This is a genuine ambiguity in mathematical notation that calculators must decide how to handle. Most scientific calculators treat the unary minus as having lower precedence than exponentiation (giving -9), matching mathematical convention. Some programming languages differ.

Precision display

1/3 * 3 should equal 1. In floating point, 1/3 is 0.333333...3 (with 15-17 significant digits), and multiplying by 3 gives 0.999999...9, not 1.0000000. A good calculator detects when a result is within floating-point epsilon of a "clean" number and displays the clean number.

Similarly, sin(180°) in floating point is not exactly 0 (it's approximately 1.22e-16). Displaying 1.22e-16 instead of 0 confuses users. Rounding results that are within machine epsilon of a known exact value is a quality-of-life feature that separates good calculators from bad ones.

I built an online scientific calculator at zovo.one/free-tools/scientific-calculator-online that handles order of operations correctly, supports implicit multiplication, manages negative number edge cases, and displays clean results. It uses a proper expression parser, not left-to-right evaluation.

I'm Michael Lip. I build free developer tools at zovo.one. 500+ tools, all private, all free.

Top comments (0)