Python数学公式计算

时间:2015-01-08 20:20:17

标签: python formula

我正在编写一个python程序来计算公式。我读了一个包含值,运算符和函数的字符串列表。

下面显示的代码接收一个字符串,例如:

['not', 1.0, 2.0, '=', 'power', 2.0, 3.0, '+']

上面的代码是数学问题的后缀版本:power(2,3)+ not(2 = 1) 程序首先计算不是(2 = 1),得到1,然后计算功率(2,3)给出9然后8 + 0得到8的返回。

到目前为止我的代码计算答案

stack = []
    def calculate(inputs): 
        if (inputs[0] == "sum"):
        inputs.remove("sum")
    for a in inputs:
        if (a) == "not":
            inputs.remove(a)
            op1, op2 = inputs[0], inputs[1]
            inputs.remove(op1)
            inputs.remove(op2)
            if op1 != op2:
                stack.append('0')
            else:
                stack.append('1') 
            continue  
        if (a) == 'power':
            inputs.remove(a)
            continue       
        if type(a) is float:
            stack.append(a)
            continue 
        op1, op2 = stack.pop(), stack.pop()
        #if a == 'power':

        if a == '+':
            stack.append(op2 + op1)
        elif a == '-':
            stack.append(op1 - op2)
        elif a == '*':
            stack.append(op2 * op1)
        elif a == '/':
            stack.append(op1 / op2)
        elif a == '=':
            if op1 != op2:
                stack.append('0')
            else:
                stack.append('1')  


    if (len(stack) > 1):
        lenStack = len(stack)-1
        for x in range(0, lenStack):
            stack.append('+')
        stack.append(_calcSum(stack))
    return stack.pop()

def _calcSum(stack):
    newStack = []
    for a in stack:
        if type(a) is float:
            newStack.append(a)
            continue
        op1, op2 = newStack.pop(), newStack.pop()
        if a == '+':
            newStack.append(op2 + op1)
        elif a == '-':
            newStack.append(op1 - op2)
        elif a == '*':
            newStack.append(op2 * op1)
        elif a == '/':
            newStack.append(op1 / op2)
    return newStack.pop()

但是我遇到了NOT和POWER语句的问题;我无法弄清楚如何自动检查这些。任何人都可能指出我正确的方向或协助我的代码?当我尝试检查'power'时,它只是跳过我剩下的代码并尝试打印堆栈 - 这是空的,导致错误。

3 个答案:

答案 0 :(得分:1)

我认为以下代码可能是您想要的:

import math

test_input = ['2', '1', '=', 'not', '2', '3', 'power', '+']

def calculate(input):
    newStack = []
    for a in input:
        print newStack

        if a == '+':
            op1, op2 = newStack.pop(), newStack.pop()
            newStack.append(op2 + op1)
        elif a == '-':
            op1, op2 = newStack.pop(), newStack.pop()
            newStack.append(op1 - op2)
        elif a == '*':
            op1, op2 = newStack.pop(), newStack.pop()
            newStack.append(op2 * op1)
        elif a == '/':
            op1, op2 = newStack.pop(), newStack.pop()
            newStack.append(op1 / op2)
        elif a == '=':
            op1, op2 = newStack.pop(), newStack.pop()
            if op1 == op2:
                newStack.append(1)
            else:
                newStack.append(0)
        elif a == 'not':
            op = newStack.pop()
            if op > 0:
                newStack.append(0)
            else:
                newStack.append(1)
        elif a == 'power':
            op1, op2 = newStack.pop(), newStack.pop()
            newStack.append(math.pow(op1, op2))
        else:
            newStack.append(float(a))

    return newStack.pop()

正如PeterE在他的评论中指出你的后缀代码是错误的。我假设您想要的后缀代码可能是2 1 = not 2 3 power +。另请注意,最终值为9+1 = 10而不是8+0 = 8

维基百科有一个很好的关于后缀代码的页面:http://en.wikipedia.org/wiki/Reverse_Polish_notation

在python代码中,一个函数实际上应该足以将所有需要的东西推送到堆栈。要实现基本实现,您可以简单地检查所有不同的操作员案例并执行任何所需的操作。如果所提供的运算符都不匹配当前元素,则可以假设该元素是一个数值,只需按下已解析的float值。

请注意,这是一个非常快速和肮脏的实现,但它可能会引导您走上正确的轨道。

答案 1 :(得分:1)

基于IXI的答案,您可以通过使用函数式编程来显着降低代码的复杂性和数量:创建从符号到要执行的操作的映射,然后在该映射中查找输入中的符号。这样做,您会发现powernot根本不是特殊的,可以轻松添加其他一元和二元运算符。您甚至可以扩展它以支持三元运算符,例如... if ... else ...(尽管您必须以后缀形式编写它们)。

BIN_OP = {"+": lambda x, y: x + y,
          "-": lambda x, y: x - y,
          "*": lambda x, y: x * y,
          "/": lambda x, y: x / y,
          "power": lambda x, y: x**y,
          "=": lambda x, y: int(x == y)}
UN_OP = {"not": lambda x: int(not x)}

def calculate(tokens):
    stack = []
    for token in tokens:
        if token in BIN_OP:
            op1, op2 = stack.pop(), stack.pop()
            operation = BIN_OP[token]
            stack.append(operation(op1, op2))
        elif token in UN_OP:
            op1 = stack.pop()
            operation = UN_OP[token]
            stack.append(operation(op1))
        else:
            stack.append(float(token))
    return stack.pop()

示例:

>>> calculate(['2', '1', '=', 'not', '2', '3', 'power', '+'])
10.0

答案 2 :(得分:1)

关于冗余细化的主题,这里是针对较少特殊情况重新构建的tobias_k解决方案的变体:

from operator import add, sub, mul, truediv, pow, eq, not_

ops = {"+": add, "-": sub, "*": mul, "/": truediv, 
       "power": pow, "=": eq, "not": not_}
# Mark how many inputs are needed
ops = {k:(1 if f is not_ else 2, f) for (k,f) in ops.items()}

def calculate(tokens):
    stack = []
    for token in tokens:
        try:
            args,func = ops[token]
            stack[-args:] = [func(*stack[-args:])]
        except KeyError:
            stack.append(float(token))
    return float(stack[-1])

示例:

>>> calculate("2 1 = not 2 3 power +".split())
9.0
>>> calculate("2 1 = not".split())
1.0
>>> calculate("2 3 power".split())
8.0

是的,我使用Python的bool类型是int的子类型,所以True实际上是1.生成9或10的区别是只需从权力参数的顺序(2**3==83**2==9)。

问题的根源仍然是您的原始输入表达式不是有效的后缀表示法,这使得评估顺序清晰,因此运算符优先级是多余的。如果not出现在它的论证之前,你怎么知道何时进行评估呢?不是(1),不是(1 == 2),而不是((1 == 2)+(3 ** 2)看起来都像是可能的解释,而且对权力没有好处。