包含简单科学运算的表达式求值

来源:互联网 发布:网络应急协调中心待遇 编辑:程序博客网 时间:2024/05/17 02:30

包含简单科学运算的表达式求值


想写个计算器,但又没有在网上找到直接可用的开源代码,于是自己试着捣鼓一下,写了这个工具类。

源代码

package mc.math;import java.math.BigDecimal;import java.util.Stack;/** * @author 明明 * <p> * 这个类用来计算算术表达式,返回计算的结果 * <p> * 支持以下运算符号: * <p> * +(加), -(减), *(乘), /(除), ((左括号), )(右括号), ^(幂), ²(平方), ³(立方),  * <p> * sin(正弦), cos(余弦), tan(正切), ln(e为底的对数), log(10为底的对数), !(阶乘), √(根号) * <p> * 支持以下常量: * <p> * π(圆周率), e(自然常数) */public class Calculator {    // s表示sin,c表示cos, t表示tan, l表示ln, o表示log, ~表示负号    private static final char ADD = '+';    private static final char SUBTRACT = '-';    private static final char MINUS = '~'; // 负号    private static final char MULTIPLY = '*';    private static final char DIVIDE = '/';    private static final char LEFT_PARENTHESIS = '(';    private static final char RIGHT_PARENTHESIS = ')';    private static final char POW = '^';    private static final char POW2 = '²';    private static final char POW3 = '³';    private static final char SIN = 's';    private static final char COS = 'c';    private static final char TAN = 't';    private static final char LN = 'l';    private static final char LOG = 'o';    private static final char FACTORIAL = '!';    private static final char SQRT = '√';//  private static final char PI = 'π';//  private static final char E = 'e';    private static final char COMMA = ',';    private Stack<Character> operatorStack;    private Stack<String> operandStack;    private static Calculator calculator = null;    private Calculator() {        operatorStack = new Stack<Character>();        operandStack = new Stack<String>();    }    private static void initCalculator() {        // Use singleton pattern(单例模式)        if (calculator == null) {            synchronized (Calculator.class) {                if (calculator == null)                    calculator = new Calculator();            }        }        calculator.operatorStack.clear();        calculator.operatorStack.push(COMMA);        calculator.operandStack.clear();    }    /**     * 计算算术表达式并返回计算结果     * @param expression 算术表达式     * @return 算术表达式的结果     */    public static String calculateExpression(String expression) {        initCalculator();        expression = expression.replaceAll("sin", "s")            .replaceAll("cos", "c")            .replaceAll("tan", "t")            .replaceAll("ln", "l")            .replaceAll("log", "o")            .replaceAll("π", String.valueOf(Math.PI))            .replaceAll("e", String.valueOf(Math.E));        int currentIndex = 0;        int count = 0;        char peekOperator;        while (currentIndex < expression.length()) {            char currentChar = expression.charAt(currentIndex);            // 右结合单目运算符直接入符号栈            if (isUnaryOperator(currentChar)) {                calculator.operatorStack.push(currentChar);                currentIndex++;            // 左结合单目运算符直接运算            } else if (currentChar == FACTORIAL || currentChar == POW2 ||                    currentChar == POW3) {                String result = calculate(calculator.operandStack.pop(), currentChar);                calculator.operandStack.push(result);                currentIndex++;            } else if (isBinaryOperator(currentChar)) { // 双目运算符                // 检查是否是负号,负号是右结合单目运算符,直接入符号栈                if (currentChar == SUBTRACT) {                    if (currentIndex == 0 || isOperator(                            expression.charAt(currentIndex - 1))) {                        calculator.operatorStack.push(MINUS);                        currentIndex++;                        continue;                    }                }                peekOperator = calculator.operatorStack.peek();                while (peekOperator != COMMA) {                    // 如果前一个运算符是右结合单目运算符                    if (isUnaryOperator(peekOperator)) {                        String result = calculate(calculator.operandStack.pop(),                                calculator.operatorStack.pop());                        calculator.operandStack.push(result);                    // 如果前一个运算符是双目运算符,并且其优先级大于等于当前运算符的优先级                    } else if (compareOperatorPriority(currentChar, peekOperator) <= 0) {                        binaryCalculate();                    } else {                        break;                    }                    peekOperator = calculator.operatorStack.peek();                }                calculator.operatorStack.push(currentChar);                currentIndex++;            } else if (currentChar == LEFT_PARENTHESIS) { // 左括号"("直接入符号栈                calculator.operatorStack.push(currentChar);                currentIndex++;            } else if (currentChar == RIGHT_PARENTHESIS) { // 右括号 )                peekOperator = calculator.operatorStack.peek();                while (peekOperator != LEFT_PARENTHESIS) {                    // 如果前一个运算符是右结合单目运算符                    if (isUnaryOperator(peekOperator)) {                        String result = calculate(calculator.operandStack.pop(),                                calculator.operatorStack.pop());                        calculator.operandStack.push(result);                    // 如果前一个运算符是双目运算符                    } else {                        binaryCalculate();                    }                    peekOperator = calculator.operatorStack.peek();                }                calculator.operatorStack.pop();                currentIndex++;            // 如果是数字            } else {                do {                    count++;                    if (currentIndex + count >= expression.length()) break;                } while (isDigitOrPoint(expression.charAt(currentIndex + count)));                calculator.operandStack.push(                        expression.substring(currentIndex, currentIndex + count));                currentIndex += count;                count = 0;            }        }        peekOperator = calculator.operatorStack.peek();        while (peekOperator != COMMA) {            // 如果前一个运算符是右结合单目运算符            if (isUnaryOperator(peekOperator)) {                String result = calculate(calculator.operandStack.pop(),                        calculator.operatorStack.pop());                calculator.operandStack.push(result);            // 如果前一个运算符是双目运算符            } else {                binaryCalculate();            }            peekOperator = calculator.operatorStack.peek();        }        return removerRedundantZero(calculator.operandStack.pop());    }    // 去除小数点后多余的0    private static String removerRedundantZero(String s) {        if (s.contains(".")) {            int startIndex = s.indexOf('.') - 1;            for (int i = startIndex + 2, sLength = s.length(); i < sLength; i++) {                if (s.charAt(i) != '0') {                    startIndex = i;                }            }            return s.substring(0, startIndex + 1);        }        return s;    }    // 双目运算    private static void binaryCalculate() {        String n2 = calculator.operandStack.pop();        String n1 = calculator.operandStack.pop();        String result = calculate(n1, n2, calculator.operatorStack.pop());        calculator.operandStack.push(result);    }    private static boolean isOperator(char c) {        // s表示sin,c表示cos, t表示tan, l表示ln, o表示log, ~表示负号        return (c == ADD ||                c == SUBTRACT ||                c == MULTIPLY ||                c == DIVIDE ||                c == POW ||                c == SIN ||                c == COS ||                c == TAN ||                c == LN ||                c == LOG ||                c == SQRT);        // π    }    // 判断是否是右结合单目运算符,是则返回true    private static boolean isUnaryOperator(char c) {        return (c == MINUS ||                c == SIN ||                c == COS ||                c == TAN ||                c == LN ||                c == LOG ||                c == SQRT);    }    // 判断是否是双目运算符,是则返回true    private static boolean isBinaryOperator(char c) {        return (c == ADD ||                c == SUBTRACT ||                c == MULTIPLY ||                c == DIVIDE ||                c == POW);    }    // 判断是否是数字或点(小数点),是则返回true    private static boolean isDigitOrPoint(char c) {        return (Character.isDigit(c) || c == '.');    }    /* 比较两个运算符的优先级,     * operator1等于operator2则返回0     * operator1大于operator2则返回大于0的数,     * operator1小于operator2则返回小于0的数     */    private static int compareOperatorPriority(char operator1, char operator2) {                               // ,  (  +  -  *  /  ^  )        int[] operatorPriority = {0, 1, 2, 2, 3, 3, 4, 5};        int index1 = 0, index2 = 0;        switch (operator1) {            case COMMA:                index1 = 0; break;            case LEFT_PARENTHESIS:                index1 = 1; break;            case ADD:                index1 = 2; break;            case SUBTRACT:                index1 = 3; break;            case MULTIPLY:                index1 = 4; break;            case DIVIDE:                index1 = 5; break;            case POW:                index1 = 6; break;            case RIGHT_PARENTHESIS:                index1 = 7; break;        }        switch (operator2) {            case COMMA:                index2 = 0; break;            case LEFT_PARENTHESIS:                index2 = 1; break;            case ADD:                index2 = 2; break;            case SUBTRACT:                index2 = 3; break;            case MULTIPLY:                index2 = 4; break;            case DIVIDE:                index2 = 5; break;            case POW:                index2 = 6; break;            case RIGHT_PARENTHESIS:                index2 = 7; break;        }        return operatorPriority[index1] - operatorPriority[index2];    }    // 双目运算    private static String calculate(String n1, String n2, char operator) {        BigDecimal bD1 = new BigDecimal(n1);        BigDecimal bD2 = new BigDecimal(n2);        switch (operator) {            case ADD: return bD1.add(bD2).toString();            case SUBTRACT: return bD1.subtract(bD2).toString();            case MULTIPLY: return bD1.multiply(bD2).toString();            case DIVIDE:                 try {                    return bD1.divide(bD2).toString();                } catch (Exception ex) {                    return bD1.divide(bD2, 100, BigDecimal.ROUND_HALF_UP).toString();                }            default: return "0";        }    }    // 单目运算    private static String calculate(String n, char operator) {        BigDecimal bd = new BigDecimal(n);        switch (operator) {            case FACTORIAL:                BigDecimal tempResult = BigDecimal.ONE;                for (int i = 2, length = bd.intValue(); i <= length; i++) {                    tempResult = tempResult.multiply(new BigDecimal(String.valueOf(i)));                }                return tempResult.toString();            case POW2: return bd.multiply(bd).toString();            case POW3: return bd.multiply(bd).multiply(bd).toString();            case MINUS: return bd.multiply(new BigDecimal("-1")).toString();            case SIN: return String.valueOf(Math.sin(bd.doubleValue()));            case COS: return String.valueOf(Math.cos(bd.doubleValue()));            case TAN: return String.valueOf(Math.tan(bd.doubleValue()));            case SQRT: return String.valueOf(Math.sqrt(bd.doubleValue()));            case LN: return String.valueOf(Math.log(bd.doubleValue()));            case LOG: return String.valueOf(Math.log10(bd.doubleValue()));            default: return "0";        }    }}
0 0
原创粉丝点击