Reputation: 61
So for the following code that calculates mathematical expressions in Reverse Polish Notation (RPN), the final calculation (output) seems to be incorrect for certain inputs.
Example inputs:
(All outputs should be floats)
def evalSimpleEqn(eqn):
result = []
for x in eqn:
if x == "add":
result.append( result.pop() + result.pop() )
elif x == "subtract":
result.append( result.pop() - result.pop())
elif x == "multiply":
result.append( result.pop() * result.pop() )
elif x == "divide":
y = ((result.pop()))
z = (result.pop())
result.append( z/y )
else:
result.append(x)
return (result[-1])
Specifically, when I input: [12, 8, "subtract", 2, "divide", 4, "divide", 1, "add"]
The function returns 0.5 instead of 1.5. How do I fix this? Thank you for any help!
Upvotes: 3
Views: 143
Reputation: 71
two changes in main code
def evalSimpleEqn(eqn):
result = []
for x in eqn:
if x == "add":
result.append( result.pop() + result.pop() )
elif x == "subtract":
# (1) reorder operands, as pop() extract firstly subtrahend and then minuend
result.append( - result.pop() + result.pop())
elif x == "multiply":
result.append( result.pop() * result.pop() )
elif x == "divide":
y = ((result.pop()))
z = (result.pop())
# (2) add 1.* to convert result to float
result.append( 1.* z/y )
else:
result.append(x)
return (result[-1])
Upvotes: 0
Reputation: 5821
Just for fun, another way to do it that is more easily extensible:
#!/usr/bin/env python
"""Example code showing how to build an easily extensible RPN calculator"""
def rpn_eval(expression):
"""Calculates the passed expression list and returns the result"""
result = []
ops = {"add":float.__radd__,
"subtract":float.__rsub__,
"multiply":float.__rmul__,
"divide":float.__rtruediv__
}
for arg in expression:
result.append(arg if arg not in ops
else ops[arg](result.pop().__float__(), result.pop()))
return result[-1]
def main():
"""main function"""
tests = [
[10, [10, 10, "add", 2, "divide"]],
[1.5, [3, 1, "multiply", 2, "divide"]],
[1.5, [12, 8, "subtract", 2, "divide", 4, "divide", 1, "add"]]
]
for ans, expr in tests:
calc_ans = rpn_eval(expr)
print '{} == {}? {}'.format(ans, calc_ans, ans == calc_ans)
if __name__ == "__main__":
main()
Upvotes: 1
Reputation: 46849
the problem is in the subtract operation: the operands are interchanged in your implementation. you just have to treat it the same way you treat the division. for addition and multiplication the order does not matter.
def rpn_eval(s):
result = []
for x in s:
print(result)
if x == "add":
result.append(result.pop() + result.pop())
elif x == "subtract":
y = result.pop()
x = result.pop()
result.append(x - y)
elif x == "multiply":
result.append(result.pop() * result.pop())
elif x == "divide":
y = result.pop()
z = result.pop()
result.append(z / y)
else:
result.append(x)
return result[-1]
and it may not be a good idea to call your function eval
that name is taken.
Upvotes: 3