[Java] Calculate the mathematical formula of addition, subtraction, multiplication and division (simple calculator) with decimals

Today’s exercise is

1. Use the keyboard to receive a mathematical formula string, including numbers, brackets, and four operation symbols of addition, subtraction, multiplication and division.
2. Analyze character strings and calculate mathematical formulas.

I searched for a blog on the Internet, describing the problem-solving method and code
https://www.cnblogs.com/menglong1108/p/11619896.html
but this one does not have any calculations on decimals, and I encountered a lot of problems during the modification process.

It tells about the idea of ​​understanding the question, I will probably sort it out:

  1. First, save the mathematical operation formula you input (ie infix expression) into a list for easy conversion into postfix expression

  2. Then traverse the infix expressions in the list and convert them into postfix expressions. The idea is as follows:
    1. Build a stack to store operators, build a list to store suffix expressions
    2. Traverse the first The infix expression of a list is placed in the new list when it encounters a number; if it encounters an operator, it should be discussed separately:

    a) When the operator stack is empty or the priority of the operator on the top of the stack is less than the priority of the operator currently traversed (for example, the priority of + and-is lower than * and /), directly into the stack
    b) When the operator stack When it is not empty and the priority of the operator on the top of the stack is greater than or equal to the priority of the operator currently traversed, the stack operation is performed in a loop and added to the list until an element with a priority lower than the current operator is encountered. After the loop is executed, the current operator is pushed onto the stack.

    3. When traversing to the parenthesis: if it is a left parenthesis, push it directly on the stack, if it encounters a right parenthesis, loop out the stack until it encounters the left parenthesis. Note: Only when the right parenthesis is encountered, the left parenthesis will be popped out of the stack.
    4. After traversing the first list, pop the rest of the stack into the new list in turn, which becomes a suffix expression.

  3. At this time, the converted suffix expression is stored in the new list, and the next step is to evaluate the suffix expression:
    1. Create a new stack
    2. Traverse the suffix expression and push the number directly onto the stack when encountering an operator. , Then the two numbers at the top of the stack and the top of the second stack are operated on by this operator. And push the result onto the stack, and finally get the only remaining stack element as the answer.

The following po comes out the complete code (including decimals), and then elaborate on where the code contains decimal operations.

package calculation;
/*import java.util.Scanner;
import java.util.List;
import java.util.ArrayList;
import java.util.Stack;*/
import java.util.*;
public class calculation {
    
    
	
	private static List<String> parseToSuffixExpression(List<String> expressionList) {
    
    
        //创建一个栈用于保存操作符
        Stack<String> opStack = new Stack<>();
        //创建一个list用于保存后缀表达式
        List<String> suffixList = new ArrayList<>();
        for(String item : expressionList){
    
    
            //得到数或操作符
            if(isOperator(item)){
    
    
                //是操作符 判断操作符栈是否为空
                if(opStack.isEmpty() || "(".equals(opStack.peek()) || priority(item) > priority(opStack.peek())){
    
    
                    //为空或者栈顶元素为左括号或者当前操作符大于栈顶操作符直接压栈
                    opStack.push(item);
                }else {
    
    
                    //否则将栈中元素出栈如队,直到遇到大于当前操作符或者遇到左括号时
                    while (!opStack.isEmpty() && !"(".equals(opStack.peek())){
    
    
                        if(priority(item) <= priority(opStack.peek())){
    
    
                            suffixList.add(opStack.pop());
                        }
                    }
                    //当前操作符压栈
                    opStack.push(item);
                }
            }else if(isNumber(item)){
    
    
                //是数字则直接入队
                suffixList.add(item);
            }else if("(".equals(item)){
    
    
                //是左括号,压栈
                opStack.push(item);
            }else if(")".equals(item)){
    
    
                //是右括号 ,将栈中元素弹出入队,直到遇到左括号,左括号出栈,但不入队
                while (!opStack.isEmpty()){
    
    
                    if("(".equals(opStack.peek())){
    
    
                        opStack.pop();
                        break;
                    }else {
    
    
                        suffixList.add(opStack.pop());
                    }
                }
            }else if(".".equals(item)){
    
    
            	//System.out.print('a');
            	suffixList.add(item);
            }else {
    
    
                throw new RuntimeException("有非法字符!");
            }
        }
        //循环完毕,如果操作符栈中元素不为空,将栈中元素出栈入队
        while (!opStack.isEmpty()){
    
    
            suffixList.add(opStack.pop());
        }
        return suffixList;
    }
    /**
     * 判断字符串是否为操作符
     * @param op
     * @return
     */
    public static boolean isOperator(String op){
    
    
        return op.equals("+") || op.equals("-") || op.equals("*") || op.equals("/");
    }

    /**
     * 判断是否为数字
     * @param num
     * @return
     */
    public static boolean isNumber(String num){
    
    
        return num.matches("^([0-9]{1,}[.][0-9]*)$") || num.matches("^([0-9]{1,})$");
    }

    /**
     * 获取操作符的优先级
     * @param op
     * @return
     */
    public static int priority(String op){
    
    
        if(op.equals("*") || op.equals("/")){
    
    
            return 1;
        }else if(op.equals("+") || op.equals("-")){
    
    
            return 0;
        }
        return -1;
    }
	
    /**
     * 将表达式转为list
     * @param expression
     * @return
     */
    private static List<String> expressionToList(String expression) {
    
    
        int index = 0;
        List<String> list = new ArrayList<>();
        do{
    
    
            char ch = expression.charAt(index);
            if(ch!=46 && (ch <= 47 || ch >= 58)){
    
    
                //是操作符,直接添加至list中
                index ++ ;
                list.add(ch+"");
            }else{
    
    
                //是数字,判断多位数的情况
                String str = "";
                while (index < expression.length() && (expression.charAt(index) >47 && expression.charAt(index) < 58 || expression.charAt(index)==46)){
    
    
                    str += expression.charAt(index);
                    index ++;
                }
                list.add(str);
                //System.out.println(str);
            }
        }while (index < expression.length());
        return list;
    }
    
	/**
     * 根据后缀表达式list计算结果
     * @param list
     * @return
     */
    private static double calculate(List<String> list) {
    
    
        Stack<Double> stack = new Stack<>();
        for(int i=0; i<list.size(); i++){
    
    
            String item = list.get(i);
            if(item.matches("^([0-9]{1,}[.][0-9]*)$") || item.matches("^([0-9]{1,})$")){
    
    
                //是数字
                stack.push(Double.parseDouble(item));
            }else {
    
    
                //是操作符,取出栈顶两个元素
                double num2 = stack.pop();
                //System.out.print(num2);
                double num1 = stack.pop();
                double res = 0;
                if(item.equals("+")){
    
    
                    res = num1 + num2;
                }else if(item.equals("-")){
    
    
                    res = num1 - num2;
                }else if(item.equals("*")){
    
    
                    res = num1 * num2;
                }else if(item.equals("/")){
    
    
                    res = num1 / num2;
                }else {
    
    
                    throw new RuntimeException("运算符错误!");
                }
                stack.push(res);
            }
        }
        return stack.pop();
    }
    
    public static boolean isInt(double calculateResult){
    
    
    	double n = calculateResult - (int)calculateResult;
    	if(n!=0){
    
    
    		return true;
    	}else{
    
    
    		return false;
    	}
    }
	
	public static void main(String []args){
    
    
		Scanner sc = new Scanner(System.in);
        String expression = sc.nextLine();
        List<String> expressionList = expressionToList(expression);
        //System.out.println("中缀表达式转为list结构="+expressionList);
        //将中缀表达式转换为后缀表达式
        List<String> suffixList = parseToSuffixExpression(expressionList);
        //System.out.println("对应的后缀表达式列表结构="+suffixList);
        //根据后缀表达式计算结果
        double calculateResult = calculate(suffixList);
        if(isInt(calculateResult)){
    
    
        	System.out.printf(expression+"=%.2f\n",calculateResult);
        }else{
    
    
        	System.out.printf(expression+"="+ (int)calculateResult);
        }
        sc.close();
}
}

This code optimizes the code in the previous po page:

  1. Can calculate decimals
  2. Like a computer on a mobile phone, if the final calculation result is an integer, the output answer does not include the decimal point; the calculation result is a decimal, and the output answer is a decimal.

The specific changes are in:

  1. Line 75 adds a regular expression that can match decimals when judging whether the value in the first list is a number
  2. Lines 102 and 109 (write the first list) added the judgment of the decimal point, if it is a decimal point, it is also added to str
  3. Line 129 adds the calculation of decimals
  4. Lines 155-162 add whether the result is an integer or a decimal.

The results are as follows:

Insert picture description here

Guess you like

Origin blog.csdn.net/qq_44899247/article/details/107187498