user10349924
user10349924

Reputation:

Calculator output wrong answer

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 

Above is my code for a functional calculator no errors at all but when I run the code and try calculator('-5 + 60 / 3^3 * 4 - 2 * 4^2') I get 35.888888888888886 but the answer should be -28.11111111111111 Is there a mistake someone in my code that I cannot find? I think it might be in the calculator section since everything else works perfectly fine with tests but I just can't find where.

I was told that one way to solve in class was that maybe using a node/stack class might help but is there any other solution than creating another class

Upvotes: 1

Views: 117

Answers (1)

sal
sal

Reputation: 3593

In the calculator big loop, when opr is -, you forgot to change the sign of mulResult.

In order to debug it, I added a print statement to the exeOpr function, so that we could see what the calculator is doing at each step. Then it was easy to determine by looking at the partial results.

The full new code is like this:

    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)

Upvotes: 1

Related Questions