Ways to evaluate math expressions - python

What are some approaches to evaluate an expression such as ((1 + 1) * 2) - 3?
Right now I am converting it to postfix form 1 1 + 2 * 3 - and then evaluate that one.
I'd like to know if there are better approaches than this.

This should work, but the Expression must be between parentheses
for example : ((4-6)+(7/9)+3) should be (((4-6)+(7/9))+3)
def evalu(express):
operat,numbers=[],[]
for i in express:
if i =='(':
pass
elif i in '0123456789':
numbers.append(int(i))
elif i in "+*-/":
operat.append(i)
elif i==")" :
oper=operat.pop()
if oper =='+':numbers.append(numbers.pop()+numbers.pop())
elif oper =='*':numbers.append(numbers.pop()*numbers.pop())
elif oper =='/':numbers.append(numbers.pop(-2)/numbers.pop())
elif oper =='-':numbers.append(numbers.pop(-2)-numbers.pop())
return numbers.pop()

Related

inaccurate results for calculations using floats - Simple solution

Many questions have been asked on StackOverflow and elsewhere about Python's confusing behaviour with calculations which use floats - often returning a result which is clearly wrong by a small amount. The explanation for this is invariably linked to. A practical simple solution is not usually provided however.
It isn't just the error (which is usually negligible) - it is more the mess and inelegance of getting a result like 3.999999999999999 for a simple sum like 8.7 - 4.7.
I have written a simple solution for this, and my question is, why isn't sthg like this automatically implemented by Python behind the scenes?
The basic concept is to convert all floats into integers, to do the operation, and then convert back appropriately into a float. The difficulties explained in the above-linked doc only apply to floats, not to ints, which is why it works. Here is the code:
def justwork(x,operator,y):
numx = numy = 0
if "." in str(x):
numx = len(str(x)) - str(x).find(".") -1
if "." in str(y):
numy = len(str(y)) - str(y).find(".") -1
num = max(numx,numy)
factor = 10 ** num
newx = x * factor
newy = y * factor
if operator == "%":
ans1 = x % y
ans = (newx % newy) / factor
elif operator == "*":
ans1 = x * y
ans = (newx * newy) / (factor**2)
elif operator == "-":
ans1 = x - y
ans = (newx - newy) / factor
elif operator == "+":
ans1 = x + y
ans = (newx + newy) / factor
elif operator == "/":
ans1 = x / y
ans = (newx / newy)
elif operator == "//":
ans1 = x // y
ans = (newx // newy)
return (ans, ans1)
This is admittedly rather inelegant and could probably be improved with a bit of thought, but it gets the job done. The function returns a tuple with the correct result (by converting to integer), and the incorrect result (automatically provided). Here are examples of how this provides accurate results, as opposed to doing it normally.
#code #returns tuple with (correct, incorrect) result
print(justwork(0.7,"%",0.1)) #(0.0, 0.09999999999999992)
print(justwork(0.7,"*",0.1)) #(0.07, 0.06999999999999999)
print(justwork(0.7,"-",0.2)) #(0.5, 0.49999999999999994)
print(justwork(0.7,"+",0.1)) #(0.8, 0.7999999999999999)
print(justwork(0.7,"/",0.1)) #(7.0, 6.999999999999999)
print(justwork(0.7,"//",0.1)) #(7.0, 6.0)
TLDR: Essentially the question is, Why are floats stored as base 2 binary fractions (which are inherently imprecise) when they could be stored the same way as integers (which Just Work)?
Three points:
the function in the question/general method proposed, while it does avoid the problem in many cases, there are many other cases, even relatively simple ones, where it has the same problem.
there is a decimal module which always provides accurate answers (even when the justwork() function in the question fails to)
using the decimal module slows things down considerably - taking roughly 100 times longer. The default approach sacrifices accuracy to prioritise speed. [Whether making this the default is the right approach is debatable].
To illustrate these three points consider the following functions, loosely based on that in the question:
def justdoesntwork(x,operator,y):
numx = numy = 0
if "." in str(x):
numx = len(str(x)) - str(x).find(".") -1
if "." in str(y):
numy = len(str(y)) - str(y).find(".") -1
factor = 10 ** max(numx,numy)
newx = x * factor
newy = y * factor
if operator == "+": myAns = (newx + newy) / factor
elif operator == "-": myAns = (newx - newy) / factor
elif operator == "*": myAns = (newx * newy) / (factor**2)
elif operator == "/": myAns = (newx / newy)
elif operator == "//": myAns = (newx //newy)
elif operator == "%": myAns = (newx % newy) / factor
return myAns
and
from decimal import Decimal
def doeswork(x,operator,y):
if operator == "+": decAns = Decimal(str(x)) + Decimal(str(y))
elif operator == "-": decAns = Decimal(str(x)) - Decimal(str(y))
elif operator == "*": decAns = Decimal(str(x)) * Decimal(str(y))
elif operator == "/": decAns = Decimal(str(x)) / Decimal(str(y))
elif operator == "//": decAns = Decimal(str(x)) //Decimal(str(y))
elif operator == "%": decAns = Decimal(str(x)) % Decimal(str(y))
return decAns
and then looping through many values to find where myAns is different to decAns:
operatorlist = ["+", "-", "*", "/", "//", "%"]
for a in range(1,1000):
x = a/10
for b in range(1,1000):
y=b/10
counter = 0
for operator in operatorlist:
myAns, decAns = justdoesntwork(x, operator, y), doeswork(x, operator, y)
if (float(decAns) != myAns) and len(str(decAns)) < 5 :
print(x,"\t", operator, " \t ", y, " \t= ", decAns, "\t\t{", myAns, "}")
=> this goes through all values to 1 d.p. from 0.1 to 99.9 - and indeed fails to find any values where myAns is different to decAns.
However if it is changed to give 2d.p. (i.e. either x = a/100 or y = b/100), then many examples appear. For example, 0.1+1.09 - this can easily be checked by typing in the console ((0.1*100)+(1.09*100)) / (100), which uses the basic method of the question, and which returns 1.1900000000000002 instead of 1.19. The source of the error is in 1.09*100 which returns 109.00000000000001. [Simply typing in 0.1+1.09 also gives the same error]. So the approach suggested in the question doesn't always work.
Using Decimal() however returns the correct answer: Decimal('0.1')+Decimal('1.09') returns Decimal('1.19').
[Note: Don't forget to enclose the 0.1 and 1.09 with quotes. If you don't, Decimal(0.1)+Decimal(1.09) returns Decimal('1.190000000000000085487172896') - because it starts with a float 0.1 which is stored inaccurately, and then converts that to Decimal - GIGO. Decimal() has to be fed a string. Taking a float, converting it to a string, and from there to Decimal, does seem to work though, the problem is only when going directly from float to Decimal].
In terms of time cost, run this:
import timeit
operatorlist = ["+", "-", "*", "/", "//", "%"]
for operator in operatorlist:
for a in range(1,10):
a=a/10
for b in range(1,10):
b=b/10
DECtime = timeit.timeit("Decimal('" +str(a)+ "') " +operator+ " Decimal('" +str(b)+ "')", setup="from decimal import Decimal")
NORMtime = timeit.timeit(str(a) +operator+ str(b))
timeslonger = DECtime // NORMtime
print("Operation: ", str(a) +operator +str(b) , "\tNormal operation time: ", NORMtime, "\tDecimal operation time: ", DECtime, "\tSo Decimal operation took ", timeslonger, " times longer")
This shows that Decimal operations consistently take around 100 times longer, for all the operators tested.
[Including exponentiation in the list of operators shows that exponentiation can take 3000 - 5000 times longer. However this is partly because Decimal() evaluates to far greater precision than normal operations - Decimal() default precision is 28 places - Decimal("1.5")**Decimal("1.5") returns 1.837117307087383573647963056, whereas 1.5**1.5 returns 1.8371173070873836. If you limit b to whole numbers by replacing b=b/10 with b=float(b) (which will prevent results with high SFs), the Decimal calculation takes around 100 times longer, as with other operators].
It could still be argued that the time cost is only significant for users performing billions of calculations, and most users would prioritise getting intelligible results over a time difference which is pretty insignificant in most modest applications.

Changing from int to int32 in Python

so I am doing an exercise from SPOJ, and it's a simple calculator. Everytime I try to submit an answer I get an NZEC error, and I wonder if it's because it should be defined as int32.
Here's my code:
import sys
n = input()
n = int(n)
i = 0
while n > i:
znak, num1, num2 = input().split()
num1 = int(num1)
num2 = int(num2)
if znak == "+":
b = num1 + num2
print(b)
elif znak == "-":
b = num1 - num2
print(b)
elif znak == "*":
b = num1 * num2
print(b)
elif znak == "/":
b = num1 / num2
print(b)
elif znak == "%":
b = num1 % num2
print(b)
i += 1
sys.exit(0)
I've tried a some "solutions" for this NZEC error, but nothing worked.
If the result should be an integer, you should use operator.floordiv, i.e. a // b, not a / b 1:
from operator import add, sub, mul, floordiv, mod
op = {'+': add, '-': sub, '*': mul, '/': floordiv, '%': mod}
for i in range(int(input())):
znak, *nums = input().split()
print(op[znak](*map(int, nums)))
By the way, the code above does exactly the same as yours, but it's around two times shorter!
How?
why check if znak is equal to something with tons of if/else statements, if you could put all the math operators in a dictionary op, and get the operator you need with op[znak]?
you're on Python 3, so you can use that nice a, *b = iterable syntax which extracts the first item of iterable into a and puts other items into a list b, which looks super nice
each op[znak] is a function that accepts two arguments, so you convert nums to integers with map(int, nums) and then pass them as separate arguments with the asterisk: *map(int, nums)
last, but not least, why use this C-style while loop index incrementing if there's the Pythonic way to do it - with range(start, stop, [step])?
finally, you don't really need the variable n, so you can plug it into range right away
Pssst, dude, feeling in need of some craziness? Take a look at how you can squeeze all this into two lines:
from operator import*
sum(0for _ in map(print,((lambda znak,*nums:{'+':add,'-':sub,'*':mul,'/':floordiv,'%':mod}[znak](*map(int,nums)))(*input().split())for _ in range(int(input())))))
Or only one line:
sum(0for _ in map(print,((lambda znak,*nums:{'+':lambda a,b:a+b,'-':lambda a,b:a-b,'*':lambda a,b:a*b,'/':lambda a,b:a//b,'%':lambda a,b:a%b}[znak](*map(int,nums)))(*input().split())for _ in range(int(input())))))
These work exactly as the first version. Now, this is just for fun, to show how powerful Python is and how messy it can be. Don't try this at home :D
1 True division vs Floor division: 1 / 10 == 0.1, but 1 // 10 == 0.
A simple solution: The idea is to split input charter into tokens preserving their orders . in our case tokens are operators and numbers so it very simple using regular expressions. [+-/*] match any of those operators or any number of digits using \d+
n = input()
import re
while n>0:
expression = input()
operator,num1,num2 = re.findall('[+-/*]|\d+',expression)
if operator == '+': print(int(num1) + int (num2))
if operator == '-': print(int(num1) - int (num2))
if operator == '*': print(int(num1) * int (num2))
if operator == '%': print(int(num1) % int (num2))
if operator == '/': print(int(num1) // int (num2))
n = n - 1

Algorithm for evaluating maths expressions using python without using multiple functions

I am trying to evaluate infix expressions using Stacks in python.
I want to know if I have the following infix expressions below:
'2 ^ ( 1 + 3 ^ 2 )'
'( 3 * 5 ) - ( 1 > 2 > 3 < 4 )'
'4 ^ ( 10 < 2 ) / 5 + 100'
how I would go on about evaluating this using 2 stacks and not calling upon multiple other functions, so that the output would be:
1024
12
103
I'm just wondering what the algorithm would be to do this. I know the standard way is to change the infix to postfix and then solve, but is there a quicker way to do this in one single function. Thank you very much.
You might want to search for the "shunting yard algorithm". It's a pretty fundamental expression evaluation algorithm, and it uses two stacks (although one is called the 'output queue').
Basically, you filter numbers from operators. Numbers go onto the output stack, operators go onto the "holding" stack. When an operator comes along that has lower precedence than what's on the holding stack, you move the contents of the holding stack to the output stack until either the holding stack is empty, or the item on the holding stack has lower precedence than the input operator.
Precedence
Remember that a + b * c - d is evaluated as (a + (b*c)) - d. Remember also that exponentiation has higher precedence than multiplication, so a * b ^ c is going to be a * (b ^ c).
EDIT:
Here's some code that doesn't work. I don't know what your operators '>' and '<' are. Apparently (10 < 2) should be 2, from the third expression?
I just implemented them as C-style booleans (1 for true, 0 false).
There's a heap of redundant code in there, because only one function. Feel free to clean that up. It modifies the Shunting Yard algorithm to perform the RPN computations on the fly. I've left in a bunch of print statements that illustrate the contents of the lists that I'm using as stacks. Feel free to do a proper job with your stack classes. In my version, pop() is pop, and append() is push.
tests = [
'2 ^ ( 1 + 3 ^ 2 )',
'( 3 * 5 ) - ( 1 > 2 > 3 < 4 )',
'4 ^ ( 10 < 2 ) / 5 + 100',
]
expected = [
1024,
12,
103,
]
def expr_eval(s):
print("EXPR:", s)
tokens = s.split()
output_stk = []
operator_stk = []
precedence = {
'(': 0,
'+':1, '-':1, '<':1, '>':1,
'*':2, '/':2,
'^':3,
}
for t in tokens:
print("OUT:", output_stk, "OP:", operator_stk)
print("Tok: ",t)
if t.isdigit():
output_stk.append(int(t))
continue
elif t == '(':
operator_stk.append(t)
continue
elif t == ')':
# End of subexpression. Do math until we find opening (
while operator_stk:
op = operator_stk.pop()
if op == '(':
break
b = output_stk.pop()
a = output_stk.pop()
if op == '-': output_stk.append(a - b)
elif op == '+': output_stk.append(a + b)
elif op == '<': output_stk.append(1 if a < b else 0)
elif op == '>': output_stk.append(1 if a > b else 0)
elif op == '*': output_stk.append(a * b)
elif op == '/': output_stk.append(a // b)
elif op == '^': output_stk.append(a ** b)
else:
raise Exception("Unknown operator: %s" % op)
print("OUT:", output_stk, "OP:", operator_stk)
continue
# Not a number - check operator precedence
prec_t = precedence[t]
while operator_stk and prec_t <= precedence[operator_stk[-1]]:
print("OUT:", output_stk, "OP:", operator_stk)
op = operator_stk.pop()
b = output_stk.pop()
a = output_stk.pop() # 'a' went on first!
if op == '-': output_stk.append(a - b)
elif op == '+': output_stk.append(a + b)
elif op == '<': output_stk.append(1 if a < b else 0)
elif op == '>': output_stk.append(1 if a > b else 0)
elif op == '*': output_stk.append(a * b)
elif op == '/': output_stk.append(a // b)
elif op == '^': output_stk.append(a ** b)
else:
raise Exception("Unknown operator: %s" % op)
operator_stk.append(t)
print("OUT:", output_stk, "OP:", operator_stk)
while operator_stk:
op = operator_stk.pop()
if op == '(':
raise Exception('Mismatched opening parenthesis!')
b = output_stk.pop()
a = output_stk.pop() # 'a' went on first!
if op == '-': output_stk.append(a - b)
elif op == '+': output_stk.append(a + b)
elif op == '<': output_stk.append(1 if a < b else 0)
elif op == '>': output_stk.append(1 if a > b else 0)
elif op == '*': output_stk.append(a * b)
elif op == '/': output_stk.append(a // b)
elif op == '^': output_stk.append(a ** b)
else:
raise Exception("Unknown operator: %s" % op)
print("OUT:", output_stk, "OP:", operator_stk)
return output_stk.pop()
for i in range(len(tests)):
r = expr_eval(tests[i])
if r == expected[i]:
print("PASS: %d = %s" % (r, tests[i]))
else:
print("FAIL: %d != %d = %s" % (r, expected[i], tests[i]))

python3 algebraic expression solve for x

I'm relatively new to python, and decided to make a calculator. Unfortunately I cant solve for x. The error is:
SyntaxError: can use starred expression only as assignment target.
I can't figure out any way around this as I want to have the person enter in the problem, and then it prints x.
Please help, And thanks for any help in advance.
My code:
import random
from datetime import datetime
import time
def ints(x,y):
x = int(x)
y = int(y)
now = datetime.now()
def solve(c, z):
c = (*z)
print(now.year)
time.sleep(1)
print("WELCOME TO THE JERAXXUS SOFTWARE")
time.sleep(2)
math = True
if math == True:
user_input = input("My name is jeraxxus, please put in 2 numbers followed by a operator, *, /, +, -, **, or %. No commas please")
user_input = str.split(user_input)
a_list = [user_input]
n1 = user_input[0]
n2 = user_input[1]
operate = user_input[2]
algebra = input("does your mathmatical equation contain algebraic values?")
if algebra == 'no':
if operate == '*':
n1 = int(n1)
n2 = int(n2)
print(n1 * n2)
elif operate == '/':
n1 = int(n1)
n2 = int(n2)
print(n1 / n2)
elif operate == '+':
n1 = int(n1)
n2 = int(n2)
print(n1 + n2)
elif operate == '-':
n1 = int(n1)
n2 = int(n2)
print(n1 - n2)
elif operate == '**':
n1 = int(n1)
n2 = int(n2)
print(n1 ** n2)
elif operate == '%':
n1 = int(n1)
n2 = int(n2)
print(n1 % n2)
elif operate != '%' and operate!= '**' and operate != '-' and operate != '+' and operate != '/' and operate != '*':
print("SHAME YOU SHOULD HAVE FOLLOWED MY COMMANDS")
math = False
elif algebra == 'yes':
problem = input("please state your algebraic problems with spaces after each operation and number, the order is crucial please have only 1 variable and have it first.")
problem = str.split(problem)
lop = problem[0]
b_list = [problem]
sovle(lop, b_list)
here are a few thing about your code:
the function ints do nothing in the end because you don't return any value, the error that you get come from c=(*z) you can't do that in a assignation, but you can do it in a function call like this fun(*argument_list).
The variable math as used there is useless because you assign it True and check it for that same value, so you enter in that if block unconditionally meaning that that if math == True is unneeded, maybe you mean while math that way you repeat that block while the variable math is true.
What is the reason of the variable a_list?, you don't use it.
In the block if algebra == 'no' you can put int conversions first and then check the operate so to avoid repeat the same code over and over again, speaking of operate the last elif is redundant because if you get there it is because it fail the other comparisons so no need to check again against every possibility, change it for a simple else.
with that little revisions you code will look like this
import random
from datetime import datetime
import time
def solve(c, z):
raise NotImplementedError("In process of programming") # an error because there is still no code for this
now = datetime.now()
print(now.year)
time.sleep(1)
print("WELCOME TO THE JERAXXUS SOFTWARE")
time.sleep(2)
math = True
while math:
user_input = input("My name is jeraxxus, please put in 2 numbers followed by a operator, *, /, +, -, **, or %. No commas please")
user_input = str.split(user_input)
#a_list = [user_input]
n1 = user_input[0]
n2 = user_input[1]
operate = user_input[2]
algebra = input("does your mathematical equation contain algebraic values?")
if algebra == 'no':
n1 = int(n1)
n2 = int(n2)
if operate == '*':
print(n1 * n2)
elif operate == '/':
print(n1 / n2)
elif operate == '+':
print(n1 + n2)
elif operate == '-':
print(n1 - n2)
elif operate == '**':
print(n1 ** n2)
elif operate == '%':
print(n1 % n2)
else:
print("SHAME YOU SHOULD HAVE FOLLOWED MY COMMANDS")
math = False
elif algebra == 'yes':
problem = input("please state your algebraic problems with spaces after each operation and number, the order is crucial please have only 1 variable and have it first.")
problem = str.split(problem)
lop = problem[0]
b_list = [problem]
solve(lop, b_list)
The no algebra part work fine, you need now figure the solve x part, if you need help with this too, just ask :)
Simple calculator
After quick search, making a simple calculator in python is easy with the use of eval, like this
def calculator():
exp = input("x= ")
print("x=", eval(exp) )
with this you can procesate any valid python expression as if you were in the IDLE.
But if for academics reason you don't want to use it, then as I tell you before, you have to make a parser of mathematical expressions, that identificate what operator is in there and arrange them according to its precedence and finally solve the expresion

prefix notation parsing in python

Right off the bat - no, this is NOT homework.
I would like to write a prefix notation parser in python (for sums presently)... for example
if given: + 2 2 it would return: 4
ideas?
Prefix notation can be very easily evaluated recursively. You basically see the first token and if it is a '+' you evaluate the sub-expressions that follow to get the values to be added and just add them up. If it is a number, you just return the number.
The following code assumes that the input is nicely formatted and is a valid expression.
#! /usr/bin/env python
from collections import deque
def parse(tokens):
token=tokens.popleft()
if token=='+':
return parse(tokens)+parse(tokens)
elif token=='-':
return parse(tokens)-parse(tokens)
elif token=='*':
return parse(tokens)*parse(tokens)
elif token=='/':
return parse(tokens)/parse(tokens)
else:
# must be just a number
return int(token)
if __name__=='__main__':
expression="+ 2 2"
print parse(deque(expression.split()))
Here's what I worked up. It keeps a stack of the operators. As it receives sufficient numbers it pops an operator and evaluates the sub-expression.
# Bring in the system module to get command line parameters
import sys
# This function takes in some binary operator, which is just an arbitrary
# string, and two values. It looks up the method associated with the
# operator, passes the two values into that method, and returns the
# method's result.
def eval_expression(operator, value_one, value_two):
if operator == "+":
return value_one + value_two
elif operator == "-":
return value_one - value_two
elif operator == "*":
return value_one * value_two
elif operator == "/":
return value_one / value_two
# Add new operators here. For example a modulus operator could be
# created as follows:
# elif operator == "mod":
# return value_one % value_two
else:
raise Exception(operator, "Unknown operator")
# This function takes in a string representing a prefix equation to
# evaluate and returns the result. The equation's values and
# operators are space delimited.
def calculate( equation ):
# Gather the equation tokens
tokens = equation.split( " " )
# Initialize the evaluation stack. This will contain the operators
# with index 0 always containing the next operator to utilize. As
# values become available an operator will be removed and
# eval_expression called to calculate the result.
eval_stack = [ ]
total = None
# Process all the equation tokens
for token in tokens:
if token.isdigit():
# Save the first value. Subsequent values trigger the evaluation
# of the next operator applied to the total and next values
token = int(token)
if total is None:
total = token
else:
total = eval_expression(eval_stack.pop(0), total, token)
else:
# Save the new operator to the evaluation stack
eval_stack.insert(0, token)
# Done! Provide the equation's value
return total
# If running standalone pass the first command line parameter as
# an expression and print the result. Example:
# python prefix.py "+ / 6 2 3 - 6"
if __name__ == '__main__':
print calculate( sys.argv[1] )
I like MAK's recursive function too.
Reverse the tokens and use a stack machine like the following:
def prefix_eval(tokens):
stack = []
for t in reversed(tokens):
if t == '+': stack[-2:] = [stack[-1] + stack[-2]]
elif t == '-': stack[-2:] = [stack[-1] - stack[-2]]
elif t == '*': stack[-2:] = [stack[-1] * stack[-2]]
elif t == '/': stack[-2:] = [stack[-1] / stack[-2]]
else: stack.append(t)
assert len(stack) == 1, 'Malformed expression'
return stack[0]
>>> prefix_eval(['+', 2, 2])
4
>>> prefix_eval(['-', '*', 3, 7, '/', 20, 4])
16
Note that stack[-1] and stack[-2] are reversed with respect to a normal stack machine. This is to accommodate the fact that it's really a prefix notation in reverse.
I should explain the several Python idioms I've used:
stack = []: There is no built-in stack object in Python, but lists are easily conscripted for the same purpose.
stack[-1] and stack[-2]: Python supports negative indices. stack[-2] refers to the second-last element of the list.
stack[-2:] = ...: This assignment combines two idioms in addition to negative indexing:
Slicing: A[x:y] refers to all the elements of A from x to y, including x but excluding y (e.g., A[3:5] refers to elements 3 and 4). An omitted number implies either the start or the end of the list. Therefore, stack[-2:] refers to every element from the second-last to the end of the list, i.e., the last two elements.
Slice assignment: Python allows you to assign to a slice, which has the effect of splicing a new list in place of the elements referred to by the slice.
Putting it all together, stack[-2:] = [stack[-1] + stack[-2]] adds together the last two elements of the stack, creates a single-element list from the sum, and assigns this list to the slice comprising the two numbers. The net effect is to replace the two topmost numbers on the stack with their sum.
If you want to start with a string, a simple front-end parser will do the trick:
def string_eval(expr):
import re
return prefix_eval([t if t in '+-*/' else int(t)
for t in re.split(r'\s+', expr)])
>>> string_eval('/ 15 - 6 3')
5
Here is example with lambda functions
ops = {
"+": (lambda a, b: a + b),
"-": (lambda a, b: a - b),
"*": (lambda a, b: a * b),
"/": (lambda a, b: a / b)
}
def eval(expression):
tokens = expression.split()
stack = []
for token in tokens:
if token in ops:
arg2 = stack.pop()
arg1 = stack.pop()
result = ops[token](arg1, arg2)
stack.append(result)
else:
stack.append(int(token))
return stack.pop()
regex that ish:
import re
prefix_re = re.compile(r"(+|-|*|/)\s+(\d+)\s+(\d+)")
for line in get_lines_to_parse():
match = prefix_re.match(line)
if match:
operand = match.group(1)
if operand == '+':
return int(match.group(2))+int(match.group(3))
elif operand == '-':
return int(match.group(2))-int(match.group(3))
#etc...
Based on other answers, but with less logic.
import operator
def eval_prefix(tokens):
operators = {'+': operator.add, '-': operator.sub, '/': operator.truediv,
'*': operator.mul, '%': operator.mod}
stack = []
for i in reversed(tokens):
if i in operators:
stack[-2] = operators[i](int(stack[-1]), int(stack[-2]))
del stack[-1]
else:
stack.append(i)
return stack[0]
This is another way to do it. I have added an "#" switcher on a, b, and c that returns b if a is positive and returns c if a is negative. I know it is a bit lengthy and inefficient but I wanted it to be universal for all operations.
def operatorhelper(index, answer):
del currentsplitline[index + 2]
del currentsplitline[index + 1]
del currentsplitline[index]
currentsplitline.insert(index, answer)
infilelines = ["+ 2 3", " - 3 2", "* 2 3", "# 1 3 4"]
for line in infilelines:
currentsplitline = line.split(" ")
for i in range(len(currentsplitline)):
try:
currentsplitline[i] = int(currentsplitline[i])
except:
continue
operatorindexes = [int(i) for i,x in enumerate(currentsplitline) if not type(x) == int]
operatorindexes = operatorindexes[::-1]
for index in operatorindexes:
answer = 0
if(isinstance(currentsplitline[index + 1], int) and isinstance(currentsplitline[index + 2], int)):
operator = currentsplitline[index]
nextnum = currentsplitline[index + 1]
secondnum = currentsplitline[index + 2]
if(operator == "+"):
answer = nextnum + secondnum
operatorhelper(index, answer)
elif(operator == "-"):
answer = nextnum - secondnum
operatorhelper(index, answer)
elif(operator == "*"):
answer = nextnum * secondnum
operatorhelper(index, answer)
elif(operator == "#"):
if(isinstance(currentsplitline[index + 3], int)):
thirdnum = currentsplitline[index + 3]
del currentsplitline[index + 3]
if(nextnum >= 0):
answer = secondnum
else:
answer = thirdnum
operatorhelper(index, answer)
print(currentsplitline[0])
def prefix(input):
op, num1, num2 = input.split(" ")
num1 = int(num1)
num2 = int(num2)
if op == "+":
return num1 + num2
elif op == "*":
return num1 * num2
else:
# handle invalid op
return 0
print prefix("+ 2 2")
prints 4, also included a multiplication operator just to show how to expand it.

Categories

Resources