计算器输出错误答案

时间:2018-10-20 21:41:50

标签: python function loops calculator

import math
def findNextOpr(txt):
    if len(txt)<=0 or not isinstance(txt,str):
        return "type error: findNextOpr"

# --- YOU CODE STARTS HERE
    if type(txt) == str:
        opr_list = ["+", "-", "*", "/", '^']
        for i in range(len(txt)):
            if txt[i] in opr_list:
                return(i)
        return(-1)




# ---  CODE ENDS HERE


def isNumber(txt):
    if not isinstance(txt, str):
        return "type error: isNumber"
    if len(txt)==0:
        return False

# --- YOU CODE STARTS HERE
    if type(txt) == str:
        try:
            float(txt)
            return True
        except ValueError:
            return False

def getNextNumber(expr, pos):

    if len(expr)==0 or not isinstance(expr, str) or pos<0 or pos>=len(expr) or not isinstance(pos, int):
        return None, None, "type error: getNextNumber"
# --- YOU CODE STARTS HERE
    txt = expr[pos:]
    oprPos = findNextOpr(txt)
    if oprPos != -1:
        if isNumber(txt[:oprPos]) == True:
            return float(txt[:oprPos]), txt[oprPos], oprPos+pos

    else:
        return None, txt[oprPos], oprPos+pos
    else:
        if isNumber(txt):
            return float(txt), None, None

    else:
        return None,None,None
# ---  CODE ENDS HERE

def exeOpr(num1, opr, num2):

#This function is just an utility function for calculator(expr). It is skipping type check

    if opr=="+":
        return num1+num2
    elif opr=="-":
        return num1-num2
    elif opr=="*":
        return num1*num2
    elif opr=="/":
        return num1/num2
    elif opr=="^":
        return num1**num2
    else:
        return "error in exeOpr"


def calculator(expr): 
    if len(expr)<=0 or not isinstance(expr,str):
        return "error"

    expr = expr.strip()
    if expr[0]!="-":
        newNumber, newOpr, oprPos = getNextNumber(expr, 0)

    else:
        newNumber, newOpr, oprPos = getNextNumber(expr, 1)
        newNumber *= -1

    if newNumber is None:
        return "error"

    elif newOpr is None:
        return newNumber

    elif newOpr=="+" or newOpr=="-":
        mode="add"
        addResult=newNumber 
        mulResult=None
        expResult=None 

    elif newOpr=="*" or newOpr=="/":
        mode="mul"
        addResult=0
        mulResult=newNumber
        expResult=None

    elif newOpr=="^":
        mode="exp"
        expResult=newNumber
        addResult=0
        mulResult=None
    pos=oprPos+1
    opr=newOpr  
    oldopr=None

    while True:
        newNumber, newOpr, oprPos = getNextNumber(expr, pos)
        if newNumber is None:
            return "input error: line B in calculator"

        elif newOpr is None:
            if mode=='add':
                if opr=='*':
                    return exeOpr(addResult, oldopr, mulResult*newNumber)
                elif opr=='/':
                    return exeOpr(addResult, oldopr, mulResult/newNumber)
                else:
                    return exeOpr(addResult, opr, newNumber)
            elif mode=='mul':
                if expResult==None:
                    expResult=0

                if mulResult==None:
                    mulResult=0
                return addResult + exeOpr(mulResult, opr, newNumber)

            elif mode=="exp":
                if expResult<0:
                    expResult=exeOpr(expResult,opr,newNumber)
                    if expResult>0:
                        expResult=-1*expResult

                else:
                    expResult=exeOpr(expResult,opr,newNumber)

                if mulResult!=0 and (oldopr=='*' or oldopr=='/'):
                    mulResult=exeOpr(mulResult,oldopr,expResult)
                    expResult=0

        elif newOpr=='+' or newOpr=='-':
            if expResult==None:
                expResult=0

            if mulResult==None:
                mulResult=0

            if mode=='add':
                addResult = exeOpr(addResult, opr, newNumber)
                mulResult = 0
                expResult= 0

            elif mode=='mul':
                addResult += exeOpr(mulResult, opr, newNumber)
                mulResult = 0
                expResult= 0

            elif mode=='exp':
                if expResult<0:
                    expResult=exeOpr(expResult,opr,newNumber)
                    if expResult>0:
                        expResult=-1*expResult
                        addResult+=expResult

                else:
                    addResult+=exeOpr(expResult,opr,newNumber)

                if oldopr=='*' or oldopr=='/':
                    expResult=exeOpr(expResult,opr,newNumber)
                    mulResult=exeOpr(mulResult,oldopr,expResult)
                    addResult+=mulResult

                mulResult = 0
                expResult = 0

            mode='add'

        elif newOpr=="*" or newOpr=="/":
            if mode=='add':                
                if opr=='-':
                    oldopr='-'
                    mulResult = newNumber

                elif opr=='+':
                    #print('here1')
                    oldopr='+'
                    mulResult = newNumber
                    mode='mul'
                else:
                    mulResult = newNumber

            elif mode=='mul':
                mulResult = exeOpr(mulResult, opr, newNumber)

            elif mode=='exp':
                if expResult<0:
                    expResult=exeOpr(expResult,opr,newNumber)
                    if expResult>0:
                        expResult=-1*expResult
                else:
                    expResult=exeOpr(expResult,opr,newNumber)

                if  mulResult !=0 and (oldopr=='*' or oldopr=='/'):
                    mulResult=exeOpr(mulResult,oldopr,expResult)
                    expResult=0

                else:
                    mulResult=expResult
                    expResult=0
                mode='mul'
        elif newOpr=='^':
            if mode=='add':
                if expResult==None:
                    expResult=0

                if mulResult==None:
                    mulResult=0

                if opr=='-':
                    expResult = -newNumber

                else:
                    expResult = newNumber
                oldopr=opr
            elif mode=='mul':
                expResult=newNumber
                oldopr=opr

            mode='exp'    

        if oprPos==None:
            break

        pos=oprPos + 1
        opr=newOpr

    if mulResult== None:
    mulResult=0

    if expResult==None:
        expResult=0

    return addResult+mulResult+expResult 

以上是我的函数计算器代码,没有错误,但是当我运行代码并尝试 计算器('-5 + 60/3 ^ 3 * 4-2 * 4 ^ 2') 我得到35.888888888888886,但答案应该是-28.11111111111111 我的代码中有人找不到我的错误吗? 我认为它可能在计算器部分中,因为其他所有内容在测试中都可以正常运行,但我找不到位置。

有人告诉我,在课堂上解决问题的一种方法是使用节点/堆栈类可能会有所帮助,但是除了创建另一个类之外,还有其他解决方案吗?

1 个答案:

答案 0 :(得分:1)

calculator大循环中,当opr-时,您忘记更改mulResult的符号。

为了调试它,我在exeOpr函数中添加了一条打印语句,以便我们可以看到计算器在每个步骤中所做的事情。通过查看部分结果很容易确定。

完整的新代码如下:

    import math

    def findNextOpr(txt):
        if len(txt) <= 0 or not isinstance(txt, str):
            return "type error: findNextOpr"

        # --- YOU CODE STARTS HERE
        if type(txt) == str:
            opr_list = ["+", "-", "*", "/", '^']
            for i in range(len(txt)):
                if txt[i] in opr_list:
                    return (i)
            return (-1)


    # ---  CODE ENDS HERE


    def isNumber(txt):
        if not isinstance(txt, str):
            return "type error: isNumber"
        if len(txt) == 0:
            return False

        # --- YOU CODE STARTS HERE
        if type(txt) == str:
            try:
                float(txt)
                return True
            except ValueError:
                return False


    def getNextNumber(expr, pos):
        if len(expr) == 0 or not isinstance(expr, str) or pos < 0 or pos >= len(expr) or not isinstance(pos, int):
            return None, None, "type error: getNextNumber"

        # --- YOU CODE STARTS HERE
        txt = expr[pos:]
        oprPos = findNextOpr(txt)
        if oprPos != -1:
            if isNumber(txt[:oprPos]):
                return float(txt[:oprPos]), txt[oprPos], oprPos + pos

            else:
                return None, txt[oprPos], oprPos + pos
        else:
            if isNumber(txt):
                return float(txt), None, None
            else:
                return None, None, None


    # ---  CODE ENDS HERE

    def exeOpr(num1, opr, num2):
        # This function is just an utility function for calculator(expr). It is skipping type check
        print("%s %s %s" % (num1, opr, num2))  # <==== DEBUGGING PRINT

        if opr == "+":
            return num1 + num2
        elif opr == "-":
            return num1 - num2
        elif opr == "*":
            return num1 * num2
        elif opr == "/":
            return num1 / num2
        elif opr == "^":
            return num1 ** num2
        else:
            return "error in exeOpr"


    def calculator(expr):
        if len(expr) <= 0 or not isinstance(expr, str):
            return "error"

        expr = expr.strip()
        if expr[0] != "-":
            newNumber, newOpr, oprPos = getNextNumber(expr, 0)

        else:
            newNumber, newOpr, oprPos = getNextNumber(expr, 1)
            newNumber *= -1

        if newNumber is None:
            return "error"

        elif newOpr is None:
            return newNumber

        elif newOpr == "+" or newOpr == "-":
            mode = "add"
            addResult = newNumber
            mulResult = None
            expResult = None

        elif newOpr == "*" or newOpr == "/":
            mode = "mul"
            addResult = 0
            mulResult = newNumber
            expResult = None

        elif newOpr == "^":
            mode = "exp"
            expResult = newNumber
            addResult = 0
            mulResult = None
        pos = oprPos + 1
        opr = newOpr
        oldopr = None

        while True:
            newNumber, newOpr, oprPos = getNextNumber(expr, pos)
            if newNumber is None:
                return "input error: line B in calculator"

            elif newOpr is None:
                if mode == 'add':
                    if opr == '*':
                        return exeOpr(addResult, oldopr, mulResult * newNumber)
                    elif opr == '/':
                        return exeOpr(addResult, oldopr, mulResult / newNumber)
                    else:
                        return exeOpr(addResult, opr, newNumber)
                elif mode == 'mul':
                    if expResult == None:
                        expResult = 0

                    if mulResult == None:
                        mulResult = 0
                    return addResult + exeOpr(mulResult, opr, newNumber)

                elif mode == "exp":
                    if expResult < 0:
                        expResult = exeOpr(expResult, opr, newNumber)
                        if expResult > 0:
                            expResult = -1 * expResult

                    else:
                        expResult = exeOpr(expResult, opr, newNumber)

                    if mulResult != 0 and (oldopr == '*' or oldopr == '/'):
                        mulResult = exeOpr(mulResult, oldopr, expResult)
                        expResult = 0

            elif newOpr == '+' or newOpr == '-':
                if expResult == None:
                    expResult = 0

                if mulResult == None:
                    mulResult = 0

                if mode == 'add':
                    addResult = exeOpr(addResult, opr, newNumber)
                    mulResult = 0
                    expResult = 0

                elif mode == 'mul':
                    addResult += exeOpr(mulResult, opr, newNumber)
                    mulResult = 0
                    expResult = 0

                elif mode == 'exp':
                    if expResult < 0:
                        expResult = exeOpr(expResult, opr, newNumber)
                        if expResult > 0:
                            expResult = -1 * expResult
                            addResult += expResult

                    else:
                        addResult += exeOpr(expResult, opr, newNumber)

                    if oldopr == '*' or oldopr == '/':
                        expResult = exeOpr(expResult, opr, newNumber)
                        mulResult = exeOpr(mulResult, oldopr, expResult)
                        addResult += mulResult

                    mulResult = 0
                    expResult = 0

                mode = 'add'

            elif newOpr == "*" or newOpr == "/":
                if mode == 'add':
                    if opr == '-':
                        oldopr = '-'
                        mulResult = -newNumber  # <====== THIS IS THE PLACE I CHANGED

                    elif opr == '+':
                        # print('here1')
                        oldopr = '+'
                        mulResult = newNumber
                        mode = 'mul'
                    else:
                        mulResult = newNumber

                elif mode == 'mul':
                    mulResult = exeOpr(mulResult, opr, newNumber)

                elif mode == 'exp':
                    if expResult < 0:
                        expResult = exeOpr(expResult, opr, newNumber)
                        if expResult > 0:
                            expResult = -1 * expResult
                    else:
                        expResult = exeOpr(expResult, opr, newNumber)

                    if mulResult != 0 and (oldopr == '*' or oldopr == '/'):
                        mulResult = exeOpr(mulResult, oldopr, expResult)
                        expResult = 0

                    else:
                        mulResult = expResult
                        expResult = 0
                    mode = 'mul'
            elif newOpr == '^':
                if mode == 'add':
                    if expResult == None:
                        expResult = 0

                    if mulResult == None:
                        mulResult = 0

                    if opr == '-':
                        expResult = -newNumber

                    else:
                        expResult = newNumber
                    oldopr = opr
                elif mode == 'mul':
                    expResult = newNumber
                    oldopr = opr

                mode = 'exp'

            if oprPos == None:
                break

            pos = oprPos + 1
            opr = newOpr

        if mulResult == None:
            mulResult = 0

        if expResult == None:
            expResult = 0

        return addResult + mulResult + expResult


    x = calculator('-5 + 60 / 3^3 * 4 - 2 * 4^2')
    print(x)