The problem: The Calculator With No Brackets
Priya's grandfather keeps an old calculator in a drawer. It has number keys and the keys
+,-,*(times),/(divide) and^(power), but no brackets and no=key. You type numbers and signs one after another, with a space between them, and the screen shows the answer.Grandpa types this and the screen shows 10:
6 8 4 2 - / +Priya is puzzled. Where did the 10 come from, when there is no
=and no brackets?At the same time, her friends Maya and Leo are arguing about a sum on the board:
8 - 3 - 2. Maya says it is 3. Leo says it is 7, "because 3 − 2 is 1, and 8 − 1 is 7". Who is right, and why could the same argument never happen on Grandpa's calculator?And a last puzzle: what exactly should Priya type to work out
2 * (9 - 4) + 6 / 2on Grandpa's calculator?No computer is needed, only pencil and paper. By the end of Lesson 1 you can answer all three. Lessons 2 and 3 go further: letters and long expressions, a stack to keep track by hand, and Python programs that evaluate and convert expressions for you.
-
Elementary and above: read the same expression in infix, prefix and postfix, and evaluate prefix and postfix by hand.
-
Elementary and above: convert infix to prefix or postfix by bracketing, and convert back again.
-
Junior and above: handle longer expressions with letters and powers, and convert directly between prefix and postfix.
-
Junior and above: evaluate expressions with a stack, by hand and in Python.
-
Lesson 1 — Three ways to write the same sum
Division: Elementary and above. This whole lesson is pencil-and-paper work. It is everything the ACSL Elementary Prefix/Infix/Postfix test asks, and it is the starting point for every other division.
Infix, prefix and postfix
The way you write sums at school puts each operator between its two numbers:
3 + 4. That is called infix notation ("in" the middle).There are two other ways to write the same sum.
Notation Where the operator goes 3 + 4is writteninfix between the two numbers 3 + 4prefix before the two numbers + 3 4postfix after the two numbers 3 4 +Prefix is also called Polish notation, after the Polish mathematician Jan Łukasiewicz who invented it, and postfix is Reverse Polish notation. Grandpa's calculator uses postfix.
The numbers (and later, letters) are called operands. The signs are operators. In all three notations the operands stay in the same order: only the operators move. Tokens (each number or operator) are written with one space between them, so
12 3 +means twelve plus three.The five operators
Operator Meaning Example +add 3 + 4is 7-subtract 9 - 4is 5*multiply 3 * 4is 12/divide 8 / 2is 4↑power 3 ↑ 2is 3 × 3 = 9The power sign has two spellings. The ACSL Elementary test writes it
^, as in3 ^ 2. The other divisions' tests, and this book, write↑, as in3 ↑ 2. Both mean the same thing, and on a keyboard you type it as^. This book always answers with↑.On the Elementary test every number is a single digit, you only ever divide by 1 or 2, and every power is 1 or 2 (
5 ↑ 2is 25, and5 ↑ 1is just 5).Infix needs rules: PEMDAS
An infix sum only has one right answer because everyone agrees on the order of operations, often remembered as PEMDAS:
-
Parentheses (brackets) first;
-
then Exponents (powers,
↑); -
then Multiplication and Division;
-
then Addition and Subtraction.
Multiplication and division are on the same level, and so are addition and subtraction. Operators on the same level are done from left to right.
-
Example 1.
8 - 3 - 2: both operators are on the same level, so go left to right. 8 − 3 = 5, then 5 − 2 = 3. Maya is right. Leo worked out8 - (3 - 2), which is a different sum.Example 2.
8 / 2 * 2: left to right, 8 / 2 = 4, then 4 × 2 = 8 (not 8 / 4 = 2).Example 3.
6 + 8 / (4 - 2): brackets first, 4 − 2 = 2; then divide, 8 / 2 = 4; then add, 6 + 4 = 10.Prefix and postfix need no brackets and no PEMDAS. The position of each operator already says which numbers it works on, so there is nothing to argue about. That is the answer to the second puzzle.
Evaluating postfix
To find the value of a postfix expression:
-
Find the first operator from the left.
-
Apply it to the two numbers just before it: the left one is the first number of the sum, the right one is the second.
-
Replace those three tokens by the answer, and repeat until one number is left.
Example 4. Grandpa's
6 8 4 2 - / +.Step Expression What happened start 6 8 4 2 - / +1 6 8 2 / +4 2 -is 4 − 2 = 22 6 4 +8 2 /is 8 / 2 = 43 106 4 +is 6 + 4 = 10-
That is the calculator's 10, and the first puzzle is solved: it is exactly
6 + 8 / (4 - 2)from Example 3.Example 5.
4 2 3 * +: the first operator is*, so2 3 *= 6, giving4 6 += 10.Watch out: order matters for
-,/and↑.9 4 -is 9 − 4 = 5, not 4 − 9. The number that comes first is always the one on the left of the operator.Evaluating prefix
In prefix each operator comes before its two numbers.
-
Find an operator that is followed straight away by two numbers.
-
Apply it to those two numbers, in order.
-
Replace the three tokens by the answer, and repeat.
The easiest operator to start with is the last one (the rightmost), since it is always followed by two numbers.
Example 6.
* + 1 3 - 7 2Step Expression What happened start * + 1 3 - 7 21 * + 1 3 5- 7 2is 7 − 2 = 52 * 4 5+ 1 3is 1 + 3 = 43 20* 4 5is 4 × 5 = 20-
Example 7.
+ * 2 3 ↑ 4 2:↑ 4 2is 4 ↑ 2 = 16 and* 2 3is 6, so the answer is 6 + 16 = 22.Infix to prefix or postfix: brackets first
This method always works.
-
Fully bracket the infix sum: put brackets round every single operator and its two operands, following PEMDAS. Each bracket then holds exactly one operator.
-
Write the operands down in the same order.
-
Take the brackets from the inside out (and left to right when two are equally deep), and move each operator to just after its two operands for postfix, or just before them for prefix.
Example 8. Convert
(7 - 3) * 2 + 8 / 2.-
Fully bracketed, following PEMDAS:
(((7 - 3) * 2) + (8 / 2)).For postfix, the inside brackets first:
Bracket Becomes (7 - 3)7 3 -((7 - 3) * 2)7 3 - 2 *(8 / 2)8 2 /the whole thing, joined by +7 3 - 2 * 8 2 / +For prefix, the same brackets with each operator in front:
(7 - 3)becomes- 7 3, then* - 7 3 2, then/ 8 2, and the whole thing is+ * - 7 3 2 / 8 2.Check: all three forms have the value 12.
Example 9. The last puzzle:
2 * (9 - 4) + 6 / 2is((2 * (9 - 4)) + (6 / 2)). In postfix it is2 9 4 - * 6 2 / +, and that is what Priya types. It evaluates to 10 + 3 = 13.Example 10. Same-level operators go left to right, so
9 - 4 - 2 + 1is(((9 - 4) - 2) + 1), which in postfix is9 4 - 2 - 1 +and in prefix is+ - - 9 4 2 1.Check yourself: evaluate your answer and the original sum. If the values differ, something moved to the wrong place.
Prefix or postfix back to infix
Work in the other direction by scanning for a small piece you can undo.
-
In prefix, find an operator followed by two operands.
-
In postfix, find two operands followed by an operator.
Replace that piece by a bracketed infix piece, which now counts as one operand, and repeat.
Example 11. The postfix
2 3 * 4 2 ↑ +Step Expression start 2 3 * 4 2 ↑ +1 (2 * 3) 4 2 ↑ +2 (2 * 3) (4 ↑ 2) +3 ((2 * 3) + (4 ↑ 2))-
Prefix to postfix, and back
To go from prefix to postfix, go through infix: first turn the prefix into a bracketed infix sum, then turn that into postfix.
Example 12. The prefix
+ * 2 3 ↑ 4 2from Example 7. To infix:↑ 4 2becomes(4 ↑ 2),* 2 3becomes(2 * 3), and the whole thing is((2 * 3) + (4 ↑ 2)). To postfix:2 3 * 4 2 ↑ +. That is exactly the expression of Example 11, and both have the value 22.Postfix to prefix works the same way, through infix. Lesson 2 shows a quicker way that skips the infix step.
Optional. This unit's folder also holds a small Python program,
assets/l1.py, that evaluates a postfix expression. You do not need it for the Elementary test: everything in this lesson is done with pencil and paper. Students going on to Lesson 2 meet it there.Elementary checklist. You can now:
-
use PEMDAS, and go left to right on the same level;
-
evaluate a postfix expression;
-
-
evaluate a prefix expression;
-
convert infix to prefix and to postfix by fully bracketing;
-
convert prefix to postfix and postfix to prefix, through infix.
That is the whole Elementary test. Exercises 1 to 9 are an Elementary practice test. Junior, Intermediate and Senior students continue with Lessons 2 and 3.
-
Lesson 2 — Longer expressions, and a stack by hand
Division: Junior and above.
A self-checker for Lesson 1
If you can run a Python program, this one evaluates a postfix expression, using exactly the "take the two numbers before the operator" idea of Lesson 1. Work each question by hand first, then use it to check yourself. Type the power sign as
^. It is saved asassets/l1.py; you do not need to understand the code yet, and Lesson 3 explains every line.Try it OPERATORS = ["+", "-", "*", "/", "^"] def apply(op, left, right): if op == "+": return left + right if op == "-": return left - right if op == "*": return left * right if op == "/": return left / right return left ** right def show(value): if value == int(value): return str(int(value)) return str(value) stack = [] top = 0 for token in input().split(): if token in OPERATORS: right = stack[top - 1] left = stack[top - 2] top = top - 2 value = apply(token, left, right) else: value = int(token) if top == len(stack): stack.append(value) else: stack[top] = value top = top + 1 print(show(stack[top - 1]))Scroll the code for more ↓
To run it, open a terminal in this unit's folder, type
python assets/l1.py, then type a postfix expression such as6 8 4 2 - / +and press Enter; it prints10. You can also feed it a file:python assets/l1.py < assets/l1/3.inchecks5 2 ^ 6 2 / -and prints22.Letters, big numbers and powers
From Junior up, operands can be numbers of any size or letters standing for numbers, such as
A B C. Letters are converted exactly like numbers: they are operands, and they never change order.The power
↑sits above*and/in PEMDAS. So2 * 3 ↑ 2is 2 × 9 = 18, not 6 ↑ 2 = 36. The questions in this book never put two↑in a row without brackets, so you never have to decide which power goes first.Example 1. Convert
(A + B * C) / (D - E) ↑ 2to prefix and postfix.Fully bracketed: the
↑binds(D - E)and2first, and the/is done last.((A + (B * C)) / ((D - E) ↑ 2))Inside out:
(B * C)→B C *, then(A + …)→A B C * +;(D - E)→D E -, then(… ↑ 2)→D E - 2 ↑; finally the/.-
Postfix:
A B C * + D E - 2 ↑ / -
Prefix:
/ + A * B C ↑ - D E 2
Watch out: the
2in↑ 2is an operand like any other, so it keeps its place in the list of operands: A, B, C, D, E, 2.-
Prefix to postfix directly
Going through infix works, but for long expressions a direct method is faster. Find an operator with its two finished operands, and rewrite that piece in the other notation inside square brackets. A bracketed piece counts as one operand from then on. When nothing is left to do, drop the brackets.
Example 2. The prefix
- * A + B C / D Eto postfix. In prefix, a piece is an operator followed by two operands.Step Expression Piece start - * A + B C / D E1 - * A [B C +] / D E+ B C→B C +2 - * A [B C +] [D E /]/ D E→D E /3 - [A B C + *] [D E /]* A [B C +]→A B C + *4 [A B C + * D E / -]- [A B C + *] [D E /]So the postfix is
A B C + * D E / -.Postfix to prefix is the same idea: in postfix a piece is two operands followed by an operator, and you rewrite it as
[operator operand operand]. Run Example 2 backwards to see it.A stack: how a machine evaluates postfix
A stack is a pile, like a pile of plates: you only ever put a plate on the top (a push) or take the top plate off (a pop).
To evaluate postfix with a stack, read the tokens from left to right:
-
an operand: push it;
-
an operator: pop the top value (it is the right operand), pop the next one (the left operand), work out left operator right, and push the answer.
At the end, the stack holds one value: the answer.
-
Example 3.
9 3 5 + * 12 4 / -, with the stack written bottom to top:Token Action Stack after 9push 9 3push 9 3 5push 9 3 5 +pop 5 and 3; 3 + 5 = 8 9 8 *pop 8 and 9; 9 × 8 = 72 72 12push 72 12 4push 72 12 4 /pop 4 and 12; 12 / 4 = 3 72 3 -pop 3 and 72; 72 − 3 = 69 69 The answer is 69. Writing the table is slower than the scanning method of Lesson 1, but it never loses track of a long expression, and it is exactly how a program does it.
Watch out: the first value you pop is the right operand. For
72 3 -you pop 3 first, and the sum is 72 − 3, not 3 − 72.A stack for prefix: read from the right
Prefix works the same way, reading the tokens from right to left. The one change: now the first value you pop is the left operand.
Example 4.
- * 2 + 3 4 / 9 3, read from the right:Token Action Stack after 3push 3 9push 3 9 /pop 9 (left) and 3 (right); 9 / 3 = 3 3 4push 3 4 3push 3 4 3 +pop 3 (left) and 4 (right); 3 + 4 = 7 3 7 2push 3 7 2 *pop 2 (left) and 7 (right); 2 × 7 = 14 3 14 -pop 14 (left) and 3 (right); 14 − 3 = 11 11 The answer is 11.
A stack in Python
A Python list can be a stack. This book keeps a list
stacktogether with a counttopof how many values are on it, and never shrinks the list:-
push a value: if
topequalslen(stack),appendit; otherwise write it over the old value atstack[top]. Then add 1 totop. -
pop: take 1 from
top; the popped value isstack[top]. -
the top value is
stack[top - 1].
Values above
topare just leftovers from earlier; the program ignores them.-
stack = [] top = 0 for value in [9, 3, 5]: if top == len(stack): stack.append(value) else: stack[top] = value top = top + 1 print("top value:", stack[top - 1], "count:", top) top = top - 1 right = stack[top] top = top - 1 left = stack[top] print("popped", right, "then", left) value = left + right if top == len(stack): stack.append(value) else: stack[top] = value top = top + 1 print("top value:", stack[top - 1], "count:", top) print("the list itself:", stack)Scroll the code for more ↓
Output
top value: 5 count: 3 popped 5 then 3 top value: 8 count: 2 the list itself: [9, 8, 5]After the two pops and one push, the stack holds 2 values (9 and 8), but the list still has 3 items: the 5 is a leftover above
top. That is why every loop in this unit usestop, neverlen(stack), to know how many values are really on the stack. Try it with another list in place of[9, 3, 5], or another operator in place of the+.Put it together: this program evaluates a postfix expression and prints the stack after each token, just like the table in Example 3. Use it to check your own stack tables. An operator pops two values (
rightfirst, thenleft) by movingtopdown 2, and the loop at the end prints the values fromstack[0]up to the top. It is saved asassets/l2.py.Try it OPERATORS = ["+", "-", "*", "/", "^"] def apply(op, left, right): if op == "+": return left + right if op == "-": return left - right if op == "*": return left * right if op == "/": return left / right return left ** right def show(value): if value == int(value): return str(int(value)) return str(value) stack = [] top = 0 for token in input().split(): if token in OPERATORS: right = stack[top - 1] left = stack[top - 2] top = top - 2 value = apply(token, left, right) else: value = int(token) if top == len(stack): stack.append(value) else: stack[top] = value top = top + 1 line = token + " :" for i in range(top): line = line + " " + show(stack[i]) print(line)Scroll the code for more ↓
Run it from this unit's folder:
python assets/l2.py < assets/l2/2.inThe input
9 3 5 + * 12 4 / -prints the nine rows of Example 3, one per token, ending with- : 69.assets/l2/3.inholds2 3 ^ 1 -, which shows a power on the stack.Lesson 3 — Evaluating and converting with Python
Division: Junior and above.
A postfix evaluator
The stack method turns straight into a program. The function
applydoes one operation, and the loop pushes operands and handles operators. Python writes the power↑as**, and the program reads it as^, the keyboard's spelling.OPERATORS = ["+", "-", "*", "/", "^"] def apply(op, left, right): if op == "+": return left + right if op == "-": return left - right if op == "*": return left * right if op == "/": return left / right return left ** right def evaluate_postfix(text): stack = [] top = 0 for token in text.split(): if token in OPERATORS: right = stack[top - 1] left = stack[top - 2] top = top - 2 value = apply(token, left, right) else: value = int(token) if top == len(stack): stack.append(value) else: stack[top] = value top = top + 1 return stack[top - 1] print(evaluate_postfix("9 3 5 + * 12 4 / -")) print(evaluate_postfix("2 9 4 - * 6 2 / +")) print(evaluate_postfix("2 3 * 4 2 ^ +"))Scroll the code for more ↓
Output
69.0 13.0 22The first line prints
69.0, not69. In Python,/always gives a decimal number, even when the division is exact (12 / 4is3.0), and the.0carries on into every later step. The answer to an ACSL question is written as a whole number when it is whole, so the program needs one more small function.def show(value): if value == int(value): return str(int(value)) return str(value) print(show(69.0)) print(show(13)) print(show(15.5))Scroll the code for more ↓
Output
69 13 15.5showcompares the value with its whole-number part: if they are equal, it prints the whole number; if not, it prints the decimal. The self-checkerassets/l1.pyfrom the start of Lesson 2 is exactlyapply, the loop ofevaluate_postfix, andshow, reading the expression withinput(). Look back at it now: you can read every line.A prefix evaluator
For prefix, walk the tokens from right to left with
range(len(tokens) - 1, -1, -1), and remember that the first value popped is now the left operand.OPERATORS = ["+", "-", "*", "/", "^"] def apply(op, left, right): if op == "+": return left + right if op == "-": return left - right if op == "*": return left * right if op == "/": return left / right return left ** right def evaluate_prefix(text): tokens = text.split() stack = [] top = 0 for i in range(len(tokens) - 1, -1, -1): token = tokens[i] if token in OPERATORS: left = stack[top - 1] right = stack[top - 2] top = top - 2 value = apply(token, left, right) else: value = int(token) if top == len(stack): stack.append(value) else: stack[top] = value top = top + 1 return stack[top - 1] print(evaluate_prefix("- * 2 + 3 4 / 9 3")) print(evaluate_prefix("+ * 2 3 ^ 4 2"))Scroll the code for more ↓
Output
11.0 22The only two lines that differ from the postfix loop are the
rangegoing backwards and the swappedleftandright. Swap them back and- * 2 + 3 4 / 9 3gives a wrong answer: try it.Converting with a stack
A stack can hold text as well as numbers. To turn postfix into prefix, push each operand as a piece of text; for an operator, pop two pieces and push one new piece, operator, left, right, joined with spaces. That is the square-bracket method of Lesson 2, done by a machine. It is saved as
assets/l3.py.Try it OPERATORS = ["+", "-", "*", "/", "^"] stack = [] top = 0 for token in input().split(): if token in OPERATORS: right = stack[top - 1] left = stack[top - 2] top = top - 2 item = token + " " + left + " " + right else: item = token if top == len(stack): stack.append(item) else: stack[top] = item top = top + 1 print(stack[top - 1])Scroll the code for more ↓
Run it from this unit's folder:
python assets/l3.py < assets/l3/1.inThe input
A B C * + D E - /prints/ + A * B C - D E.assets/l3/3.inruns Lesson 2's Example 2 backwards:A B C + * D E / -prints- * A + B C / D E. To go from prefix to postfix instead, read from the right, and push left, right, operator.Longer expressions and non-whole answers
Division: Intermediate and above.
Intermediate and Senior questions use longer expressions, and a division does not have to come out whole. The stack method is the same; just keep the fractions. Write a non-whole answer as a decimal. In this book every division ends after a few decimal places (halves, quarters, tenths and so on), never a repeating decimal such as 1/3.
Example 1.
7 2 / 3 4 * +: 7 / 2 = 3.5, 3 × 4 = 12, and 3.5 + 12 = 15.5.Example 2.
3 4 ↑ 5 * 9 2 / 6 * - 8 /Piece Value 3 4 ↑81 81 5 *405 9 2 /4.5 4.5 6 *27 405 27 -378 378 8 /47.25 A fraction in the middle can still end in a whole answer: in
9 4 / 2 ↑ 16 *, the value 9 / 4 = 2.25, and 2.25 ↑ 2 = 5.0625, but 5.0625 × 16 = 81.Letters with values. A question may give values for the letters, such as A = 3 and B = 5. Replace each letter by its value, then evaluate as usual.
Optional aside: expression trees
Not assessed.
An expression can also be drawn as a tree: each operator is a branch point with its left operand below-left and its right operand below-right. Here is
(A + B * C) / (D - E) ↑ 2from Lesson 2:/ / \ + ↑ / \ / \ A * - 2 / \ / \ B C D EReading the tree in three orders gives the three notations:
-
prefix: the operator, then its left side, then its right side:
/ + A * B C ↑ - D E 2; -
infix: the left side, then the operator, then the right side (with brackets);
-
postfix: the left side, then the right side, then the operator:
A B C * + D E - 2 ↑ /.
You will meet trees again later in the book; for now, the stack is all you need.
-
-
Elementary and above: postfix puts each operator after its two operands and prefix puts it before, so neither needs brackets:
6 8 4 2 - / +is 10. -
Elementary and above: to convert infix, bracket every operation first, keep the operands in order, and take equal precedence left to right (
8 - 3 - 2is 3). -
Junior and above: a stack evaluates postfix left to right: push each number, and let each operator pop two and push its result. For prefix, read from the right.
-
- Junior and above: in Python, a list and a
topcount make that stack.
You can now evaluate and convert between all three notations, by hand and with a program.
- Junior and above: in Python, a list and a