1

As part of an assignment, I am creating a function that takes in a string, which is an equation. here is an example of one: 48+6x6/3=6x8-9x2. The compute function takes one side of the equal sign and evaluates it. I am not too concerned with splitting the equation. I believe I can just slice it with s[:s.find("=")].

My main problem is the compute function itself. I will post where I am with it so far. The commented out part was stuff I was trying to deal with double digits but I cannot figure out a logical way to do that. I would like some help thinking about this.

I was told not to use eval because doing eval on an equation "2+3*5-11/2*88+153" would not be easy due to operator precedence--or lack thereof. My program should not obey the normal operator precedence rules. Instead it is supposed to evaluate purely from left to right.

 def compute(s):
    result = 0
    a = 1
    for a in range(len(s)):

    #while s[a].isdigit():
        #result = (result * 10) + int(s[a])
        #a += 1

    if s[a] == '/':

        result = result / int(s[a + 1])

    elif s[a] == '+':

        result = result + int(s[a + 1])

    elif s[a] == 'x' or s[a] == '*' or s[a] == 'X':

        result = result * int(s[a + 1])
    elif s[a] == '-':
        result = result - int(s[a + 1])
    else:
        result += int(s[a])
    a += 1
    return result

 print(compute("48+6x6/3") == 108) 

EDIT this works for single digits. Maybe we can get this to work with multiple digits

 def compute(s):
    result = int(s[0])
    op = 0
    a = 1
    while a < len(s):
        if s[a] == '/':
        result /= int(s[a + 1])
    elif s[a] == '+':
        result += int(s[a + 1])
    elif s[a] == '*':
        result *= int(s[a + 1])
    elif s[a] == '-':
        result -= int(s[a + 1])
    a += 1
    return int(result)
  • Still not clear to me. `eval` will simply compute the equation in the input. If the input is unclear, like in your example, writing an algorithm won't help at all. – Dunno Sep 30 '14 at 21:09
  • In the problem, evaluation is strictly left to right. Since I am forcing left to right, the need for eval is removed. so doing something like `eval(str(eval(“2+3”))+”*5”)` will get very nasty for longer equations. – darksoulsfan Sep 30 '14 at 21:17
  • Using `eval` would, in fact, be trivial as long as you stick to `*` for multiplication. It sounds more like you are expected to write code that correctly handles operator precedence, so that you correctly evaluate `6 + 3 * 9` as `6 + (3 * 9)` rather than simply going left to right and treating it (incorrectly) as `(6 + 3) * 9` – chepner Sep 30 '14 at 21:25
  • Yeah I was told to break it down to number operator number operator. I am just not getting the logic in how to do it though. – darksoulsfan Sep 30 '14 at 21:27
  • @chepner It sounds like the opposite: the program should *not* correctly handle operator precedence. I've edited that into the question based on the OP's comment. – John Kugelman Sep 30 '14 at 21:46
  • @darksoulsfan I presume the intent of this assignment is that you write your own parser/evaluator rather than use some built-in library. Is that correct? – John Kugelman Sep 30 '14 at 21:49
  • Then is the expected output of the print statement "False"? The comparison is `True` if correct precedence is used instead of strictly going left to right. – chepner Sep 30 '14 at 21:49
  • Yes mainly because the next step is t make a function that "blacks out" two numbers when there are two equations set to equal each other but do not initially. I think I can handle that once I can compute one side. – darksoulsfan Sep 30 '14 at 21:50
  • By your description it should be: print(compute("48+6x6/3") == 108) – KostasT Sep 30 '14 at 21:56
  • My current problem is taking the second portion of code and making it able to use multidigit numbers. – darksoulsfan Oct 01 '14 at 00:05

2 Answers2

3

using eval can be very dangerous if you accept strings to evaluate from untrusted input. for example Suppose the string being evaluated is "os.system('rm -rf /')" ? It will really start deleting all the files on your computer.

So you can parse it with python's internal compiler :

import compiler
eq="48+6*6/3"
ast= compiler.parse( eq )

>>> compiler.parse( eq )
Module(None, Stmt([Discard(Add((Const(48), Div((Mul((Const(6), Const(6))), Const(3))))))]))
>>>

Also you can use sympy that is a Python library for symbolic mathematics. It aims to become a full-featured computer algebra system (CAS) while keeping the code as simple as possible in order to be comprehensible and easily extensible. SymPy is written entirely in Python and does not require any external libraries.

Mazdak
  • 105,000
  • 18
  • 159
  • 188
0

You can use Polish notation. http://en.wikipedia.org/wiki/Polish_notation This is a stack based algorithm for parsing and evaluating data. It is quite simple and widely used.

KostasT
  • 217
  • 1
  • 3