2021SC@SDUSC
Calculator classes include calculator class, BaseCalculator class and ScienceCalculator class. The calculator class is used to represent the state of the calculator. BaseCalculator class is used to calculate basic mathematical expressions (addition, subtraction, multiplication and division, including e operation, which is used to calculate 2E (- 16) decimals, or 3E(15) super large numbers). ScienceCalculator class is used to complete scientific operations, such as sin, cos, tan, etc, The scientific mathematical expression is transformed into the basic mathematical expression that can be completed by the basic operator BaseCalculator class
This paper studies the calculation of infix expressions in the BaseCalculator class
The stack based algorithm is used, and an element class is used to represent each element in the suffix expression
private class Ele { public boolean isNum; public double o; public char op; public Ele(double o,boolean isNum){ this.isNum=isNum; this.o=o; } public Ele(char op,boolean isNum) { this.isNum = isNum; this.op = op; } }
Used for suffix expression evaluation.
Judge whether it is a number
private boolean isNum(char c){ return (c-'0'>=0&&c-'0'<=9)||c=='.'; }
The operate method provides simple four sum E operations
private double operate(double a, char oper, double b) { switch (oper) { case '+': return a + b; case '-': return a - b; case '×': return a * b; case '/': if (b == 0) { return Double.MAX_VALUE; //Handling exceptions } return a / b; case 'E': return Double.parseDouble(String.valueOf(a+"E"+(int)b)); default: return 0; } }
Next is the key operation
First initialize a queue and number stack, character stack
Stack<Character> operStack = new Stack<>(); Queue<Ele> eleQueue = new LinkedList<>(); Stack<Double> numStack = new Stack<>();
Infix expression to suffix expression
- Initialize two stacks: the operator stack s1 and the queue s2 storing suffix expressions; Scan infix expression from left to right; When an operand is encountered, press it into s2;
- When an operator is encountered, compare its priority with that of s1 stack top operator: if s1 is empty or the stack top operator is an open parenthesis "(", this operator is directly put on the stack;
- Otherwise, if the priority is higher than the operator at the top of the stack, the operator is also pushed into s1 (note that the priority is higher or the same when converted to prefix expression, but the same case is not included here);
- Otherwise, pop up the operator at the top of s1 stack and press it into s2. Go to (4-1) again and compare it with the new operator at the top of s1. When parentheses are encountered:
- If it is the left bracket "(", press s1 directly;
- If it is the closing parenthesis ")", the operators at the top of s1 stack will pop up in turn and press s2 until the left parenthesis is encountered. At this time, this pair of parentheses will be discarded;
- Repeat steps 2 to 5 until the rightmost side of the expression; pop up the remaining operators in s1 and press them into s2 in turn;
- Pop up the elements in s2 in turn and output them. The reverse order of the result is the suffix expression corresponding to the infix expression (the reverse order is not required when converting to prefix expression)
int firstIndex = 0; int i=0; while (i < math.length()) { char charOfMath = math.charAt(i); if (charOfMath == '(') { operStack.push(charOfMath); i++; } else if (charOfMath == ')') { while (operStack.peek() != '(') { eleQueue.offer(new Ele(operStack.pop(), false)); } operStack.pop(); i++; }else if(isNum(charOfMath)){ firstIndex=i; while (++i<math.length()&&isNum(math.charAt(i))); double num; try { num = Double.parseDouble(math.substring(firstIndex, i)); } catch (NumberFormatException e) { return Double.MAX_VALUE; } eleQueue.offer(new Ele(num,true)); }else{ //Description - is a monocular operator if (charOfMath == '-') { if (i == 0) { firstIndex=0; while (++i<math.length()&&isNum(math.charAt(i))); double num; try { num = Double.parseDouble(math.substring(firstIndex, i)); } catch (NumberFormatException e) { return Double.MAX_VALUE; } eleQueue.offer(new Ele(num,true)); continue; } else if (math.charAt(i - 1)=='(') { //Indicates that this is a unary operator firstIndex=i; while (++i<math.length()&&isNum(math.charAt(i))); double num; try { num = Double.parseDouble(math.substring(firstIndex, i)); } catch (NumberFormatException e) { return Double.MAX_VALUE; } eleQueue.offer(new Ele(num,true)); continue; } } while (operStack.size() >= 0) { if (operStack.size() == 0 || operStack.peek() == '(') { operStack.push(charOfMath); break; } else { if (operMap.get(operStack.peek()) < operMap.get(charOfMath)) { operStack.push(charOfMath); break; } else { eleQueue.offer(new Ele(operStack.pop(), false)); } } } i++; } } while (operStack.size()>0){ eleQueue.offer(new Ele(operStack.pop(),false)); }
Finally, check the suffix expression for calculation
Scan the suffix expression from left to right. If it is an operand, press it into the operand stack s3. If it is an operator, two operands will pop up continuously (Note: the first operand pops up later and the second operand pops up first) , then operate the operator, press the newly generated operand into the stack, and repeat until the suffix expression is swept. There is only one number in stack s3, which is the final result.
while (eleQueue.size() > 0) { if (eleQueue.element().isNum) { numStack.push(eleQueue.poll().o); } else { char op = eleQueue.poll().op; double second= numStack.pop(); double first = numStack.pop(); numStack.push(operate(first, op, second)); } } return numStack.peek();