Masco
Masco

Reputation: 61

For loop calculation incorrect

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

Answers (3)

Trigremm
Trigremm

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

Harvey
Harvey

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

hiro protagonist
hiro protagonist

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

Related Questions