java实现简单计算器,支持整数计算、小数计算和精确计算,支持正负数

为了使用简单数学表达式做验证码,就要计算生成的表达式的计算结果,就去看了下数学表达式计算的方法。本来只计算简单的整型加减法的,但是最后整理了下,能计算小数和乘除。

核心算法:

以整数计算为例

public Integer calculate(String[] expr) throws IllegalOperandException {
        Stack numStk = new Stack();  //操作数栈
        Stack opStk = new Stack();  //操作符栈
        for (String s : expr) {
            if (isOperand(s)) {  //遇到数字,直接压栈
                int num = Integer.parseInt(s);
                numStk.push(num);
            } else if (s.equals("(")) {  //遇到左括号,直接压栈
                opStk.push(s);
            } else if (s.equals(")")) {
                while (true) {
                    String op = opStk.pop();
                    if (op.equals("("))  //弹出左括号,结束
                        break;
                    else {  //不是左括号,则为操作符,进行运算
                        int right = numStk.pop();
                        int left = numStk.pop();
                        int re = operate(left, right, op);
                        numStk.push(re);
                    }
                }
            } else {  //+ - / *
                int priority = getPriority(s);//当前操作符优先级

                while (true) {
                    if (opStk.empty() || priority > getPriority(opStk.peek())) { //操作符栈为空 或 当前符号优先级比栈顶符号优先级高,直接入栈
                        opStk.push(s);
                        break;
                    } else {
                        int right = numStk.pop();
                        int left = numStk.pop();
                        String op = opStk.pop();
                        int re = operate(left, right, op);
                        numStk.push(re);
                    }
                }
            }
        }
        while (!opStk.empty()) {  //对栈中剩余数进行运算
            int right = numStk.pop();
            int left = numStk.pop();
            String op = opStk.pop();
            int re = operate(left, right, op);
            numStk.push(re);
        }
        return numStk.pop();
    }

 

测试:java实现简单计算器,支持整数计算、小数计算和精确计算,支持正负数_第1张图片

 计算结果:

java实现简单计算器,支持整数计算、小数计算和精确计算,支持正负数_第2张图片

验证:

java实现简单计算器,支持整数计算、小数计算和精确计算,支持正负数_第3张图片

 

代码结构

 

java实现简单计算器,支持整数计算、小数计算和精确计算,支持正负数_第4张图片

CalculatorUtil:包含了工具方法

java实现简单计算器,支持整数计算、小数计算和精确计算,支持正负数_第5张图片

 

其他两种计算器的计算实现都是参照整数计算来改写的,把Integer换成了Double或BigDecimal而已

源文件们

Calculators.java

package my.Calculator;

public class Calculators {

    public static SimpleIntegerCalculator newSimpleIntegerCalculator() {
        return new SimpleIntegerCalculator();
    }

    public static DoubleCalculator newDoubleCalculator() {
        return new DoubleCalculator();
    }

    public static PreciseCalculator newPreciseCalculator() {//默认保留6位小数,四舍五入
        return new PreciseCalculator();
    }

    public static PreciseCalculator newPreciseCalculator(int scale) {//自己指定保留小数位数,四舍五入
        return new PreciseCalculator(scale);
    }

    public static PreciseCalculator newPreciseCalculator(int scale, int roundMode) {//自己指定保留小数位数和舍入方式
        return new PreciseCalculator(scale, roundMode);
    }
}

 CalculatorUtil.java

package my.Calculator;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

import my.Calculator.Exceptions.IllegalExpressionException;
import my.Calculator.Exceptions.IllegalOperandException;

class CalculatorUtil {
    //得到操作符优先级
    static int getPriority(String op) {  //获取操作符优先级
        if (op.equals("+") || op.equals("-")) {
            return 1;
        } else if (op.equals("*") || op.equals("/")) {
            return 2;
        } else if (op.equals("(")) {
            return 0;
        }
        return 0;
    }

    //判断是操作数
    static boolean isOperand(String str) throws IllegalOperandException {
        boolean isOperand = false;
        if (str.charAt(0) == '-') {  //处理负数
            if (str.length() == 1) {
                return false;
            } else {
                for (int i = 1; i < str.length(); i++) {

                    if (str.charAt(i) == '.') {
                        if (!isOperand) {
                            isOperand = true;
                            continue;
                        } else
                            throw new IllegalOperandException("\"" + str + "\"" + "is not a operand");
                    }


                    if (!Character.isDigit(str.charAt(i))) {
                        return false;
                    }
                }
            }
        } else {
            for (int i = 0; i < str.length(); i++) {

                if (str.charAt(i) == '.') {
                    if (!isOperand) {
                        isOperand = true;
                        continue;
                    } else
                        throw new IllegalOperandException("\"" + str + "\"" + "is not a operand");
                }

                if (!Character.isDigit(str.charAt(i))) {
                    return false;
                }
            }
        }
        return true;
    }

    //解析表达式为数组
    static String[] parseExpression(String expression) throws IllegalExpressionException {
        if (!validate(expression))
            throw new IllegalExpressionException();

        expression = expression.replace(" ", "");//去掉空格

        List exp = new ArrayList();
        int l = expression.length();//表达式长度
        int i = 0;
        while (true) {

            if (i >= l)
                break;

            char c = expression.charAt(i);
            if (Character.isDigit(c)) {//如果开头为数字,则找全数字部分
                StringBuilder sb = new StringBuilder();
                for (int j = i; j < l; j++) {
                    char cc = expression.charAt(j);
                    if (Character.isDigit(cc) || cc == '.') {
                        sb.append(cc);
                        i++;
                    } else {
                        break;
                    }
                }
                exp.add(sb.toString());
            }

            if (i >= l)
                break;

            c = expression.charAt(i);
            if (c == '-') {
                if (i > 0 &&//不是第一个才有可能是负号,所以i>0才可能是减号
                        (Character.isDigit(expression.charAt(i - 1)) ||
                                expression.charAt(i - 1) == ')')) {//前面一个字符为数字或右括号,那么就为操作符减号 如 8-1,(1+2)-1
                    exp.add(String.valueOf(c));
                    i++;
                } else {//否则为负号
                    StringBuilder sb = new StringBuilder();
                    sb.append(c);//负号
                    i++;
                    for (int j = i; j < l; j++) {//找数字部分
                        char cc = expression.charAt(j);
                        if (Character.isDigit(cc) || cc == '.') {
                            sb.append(cc);
                            i++;
                        } else {
                            break;
                        }
                    }
                    exp.add(sb.toString());
                }

            } else {
                //剩下的就是+ * / 了

                exp.add(String.valueOf(expression.charAt(i)));
                i++;
            }
        }
        return exp.toArray(new String[exp.size()]);
    }

    //两个数运算
    static Integer operateInteger(Integer a, Integer b, String op) {
        Integer result = 0;
        if (op.equals("+"))
            result = a + b;
        else if (op.equals("-"))
            result = a - b;
        else if (op.equals("*"))
            result = a * b;
        else if (op.equals("/"))
            result = a / b;
        return result;
    }
    static Double operateDouble(Double a, Double b, String op) {
        Double result = 0.0;
        if (op.equals("+"))
            result = a + b;
        else if (op.equals("-"))
            result = a - b;
        else if (op.equals("*"))
            result = a * b;
        else if (op.equals("/"))
            result = a / b;
        return result;
    }
    static BigDecimal operateBigDecimal(BigDecimal a, BigDecimal b, String op) {
        BigDecimal result = null;
        if (op.equals("+"))
            result = a.add(b);
        else if (op.equals("-"))
            result = a.subtract(b);
        else if (op.equals("*"))
            result = a.multiply(b);
        else if (op.equals("/"))
            result = a.divide(b, 32, BigDecimal.ROUND_HALF_UP);
        return result;
    }

    //计算整数表达式
    static Integer calculateInteger(String[] expr) throws Exceptions.IllegalOperandException {
        Stack numStk = new Stack();  //操作数栈
        Stack opStk = new Stack();  //操作符栈
        for (String s : expr) {
            if (isOperand(s)) {  //遇到数字,直接压栈
                Integer num = Integer.valueOf(s);
                numStk.push(num);
            } else if (s.equals("(")) {  //遇到左括号,直接压栈
                opStk.push(s);
            } else if (s.equals(")")) {
                while (true) {
                    String op = opStk.pop();
                    if (op.equals("("))  //弹出左括号,结束
                        break;
                    else {  //不是左括号,则为操作符,进行运算
                        Integer right = numStk.pop();
                        Integer left = numStk.pop();
                        Integer re = operateInteger(left, right, op);
                        numStk.push(re);
                    }
                }
            } else {  //+ - / *
                Integer priority = getPriority(s);//当前操作符优先级

                while (true) {
                    if (opStk.empty() || priority > getPriority(opStk.peek())) { //操作符栈为空 或 当前符号优先级比栈顶符号优先级高,直接入栈
                        opStk.push(s);
                        break;
                    } else {
                        Integer right = numStk.pop();
                        Integer left = numStk.pop();
                        String op = opStk.pop();
                        Integer re = operateInteger(left, right, op);
                        numStk.push(re);
                    }
                }
            }
        }
        while (!opStk.empty()) {  //对栈中剩余数进行运算
            Integer right = numStk.pop();
            Integer left = numStk.pop();
            String op = opStk.pop();
            Integer re = operateInteger(left, right, op);
            numStk.push(re);
        }
        return numStk.pop();
    }
    //计算double表达式
    static Double calculateDouble(String[] expr) throws IllegalOperandException {
    Stack numStk = new Stack<>();  //操作数栈
    Stack opStk = new Stack();  //操作符栈
    for (String s : expr) {
        if (isOperand(s)) {  //遇到数字,直接压栈
            double num = Double.parseDouble(s);
            numStk.push(num);
        } else if (s.equals("(")) {  //遇到左括号,直接压栈
            opStk.push(s);
        } else if (s.equals(")")) {
            while (true) {
                String op = opStk.pop();
                if (op.equals("("))  //弹出左括号,结束
                    break;
                else {  //不是左括号,则为操作符,进行运算
                    double right = numStk.pop();
                    double left = numStk.pop();
                    double re = operateDouble(left, right, op);
                    numStk.push(re);
                }
            }
        } else {  //+ - / *
            int priority = getPriority(s);//当前操作符优先级

            while (true) {
                if (opStk.empty() || priority > getPriority(opStk.peek())) { //操作符栈为空 或 当前符号优先级比栈顶符号优先级高,直接入栈
                    opStk.push(s);
                    break;
                } else {
                    double right = numStk.pop();
                    double left = numStk.pop();
                    String op = opStk.pop();
                    double re = operateDouble(left, right, op);
                    numStk.push(re);
                }
            }
        }
    }
    while (!opStk.empty()) {  //对栈中剩余数进行运算
        double right = numStk.pop();
        double left = numStk.pop();
        String op = opStk.pop();
        double re = operateDouble(left, right, op);
        numStk.push(re);
    }
    return numStk.pop();
}

    //判断为空或者空
    static boolean validate(String... s) {
        for (String s1 : s) {
            if (s1 == null || s1 == "")
                return false;
        }
        return true;
    }


}

SimpleIntegerCalculator.java

package my.Calculator;

import my.Calculator.Exceptions.IllegalExpressionException;
import my.Calculator.Exceptions.IllegalOperandException;

import static my.Calculator.CalculatorUtil.*;

public class SimpleIntegerCalculator {



    /**
     * 计算无分割符的表达式,如:2*(-32+1),由于要解析表达式,所以性能更低
     *
     * @param expression
     * @return
     * @throws IllegalOperandException
     * @throws IllegalExpressionException
     */
    public Integer calculate(String expression) throws IllegalOperandException, IllegalExpressionException {
        if (!validate(expression))
            throw new IllegalExpressionException();
        String[] expr = parseExpression(expression);
        return calculateInteger(expr);
    }


    /**
     * 计算有分隔符的表达式 如: 2;*;(;-32;+;1;)
     *
     * @param expression 表达式
     * @param separator  分隔符
     * @return
     * @throws IllegalOperandException
     * @throws IllegalExpressionException
     */
    public Integer calculate(String expression, String separator) throws IllegalOperandException, IllegalExpressionException {
        return calculate(expression, separator, true);
    }
    /**
     * 计算有分隔符的表达式
     *
     * @param expression  表达式
     * @param separator   每个操作符,数字间的分隔符,不能以空格作为分隔符
     * @param removeSpace 是否去掉空格。如果不能确定表达式中是否有空格,则要指定 removeSpace 为true;如果表达式规则,则指定为false,这样会带来性能上的略微提升
     * @return
     * @throws IllegalOperandException
     * @throws IllegalExpressionException
     */
    public Integer calculate(String expression, String separator, boolean removeSpace) throws IllegalOperandException, IllegalExpressionException {
        if (!validate(expression))
            throw new IllegalExpressionException();
        if (removeSpace)
            expression = expression.replace(" ", "");
        String[] expr = expression.split(separator);
        return calculateInteger(expr);
    }



}


DoubleCalculator.java

package my.Calculator;

import my.Calculator.Exceptions.IllegalExpressionException;
import my.Calculator.Exceptions.IllegalOperandException;

import static my.Calculator.CalculatorUtil.*;
public class DoubleCalculator {


    /**
     * 计算有分隔符的表达式 如: 2;*;(;-32;+;1;)
     *
     * @param expression 表达式
     * @param separator  分隔符
     * @return
     * @throws IllegalOperandException
     * @throws IllegalExpressionException
     */
    public Double calculate(String expression, String separator) throws IllegalOperandException, IllegalExpressionException {
        return calculate(expression, separator, true);
    }

    /**
     * 计算有分隔符的表达式
     *
     * @param expression  表达式
     * @param separator   每个操作符,数字间的分隔符,不能以空格作为分隔符
     * @param removeSpace 是否去掉空格。如果不能确定表达式中是否有空格,则要指定 removeSpace 为true;如果表达式规则,则指定为false,这样会带来性能上的略微提升
     * @return
     * @throws IllegalOperandException
     * @throws IllegalExpressionException
     */
    public Double calculate(String expression, String separator, boolean removeSpace) throws IllegalOperandException, IllegalExpressionException {
        if (!validate(expression))
            throw new IllegalExpressionException();
        if (removeSpace)
            expression = expression.replace(" ", "");
        String[] expr = expression.split(separator);
        return calculateDouble(expr);
    }

    /**
     * 计算无分割符的表达式,如:2*(-32+1),由于要解析表达式,所以性能更低
     *
     * @param expression
     * @return
     * @throws IllegalOperandException
     * @throws IllegalExpressionException
     */
    public Double calculate(String expression) throws IllegalOperandException, IllegalExpressionException {
        if (!validate(expression))
            throw new IllegalExpressionException();
        String[] expr = parseExpression(expression);
        return calculateDouble(expr);
    }



}

PreciseCalculator.java

package my.Calculator;

import java.math.BigDecimal;
import java.util.Stack;
import my.Calculator.Exceptions.IllegalExpressionException;
import my.Calculator.Exceptions.IllegalOperandException;
import static my.Calculator.CalculatorUtil.*;
public class PreciseCalculator {

    public final static int HALF_UP = BigDecimal.ROUND_HALF_UP; //四舍五入
    public final static int HALF_DOWN = BigDecimal.ROUND_HALF_DOWN;//五舍六入
    public final static int HALF_EVEN = BigDecimal.ROUND_HALF_EVEN;//银行家舍入方式,相比四舍五入,舍入概率更一致
    public final static int DOWN = BigDecimal.ROUND_DOWN;//直接舍去后面的数
    public final static int UP = BigDecimal.ROUND_UP;//后面只要有值,直接进位

    int scale, roundingMode;

    public PreciseCalculator() {
        scale = 6;//默认保留6位小数,舍入方式位四舍五入
        roundingMode = HALF_UP;
    }

    public PreciseCalculator(int scale) {
        this.scale = scale;
        roundingMode = HALF_UP;
    }

    public PreciseCalculator(int scale, int roundingMode) {
        this.scale = scale;
        this.roundingMode = roundingMode;
    }


    public BigDecimal calculate(String expression) throws IllegalOperandException, IllegalExpressionException {
        if (!validate(expression))
            throw new IllegalExpressionException();
        String[] expr = parseExpression(expression);
        return calculateBigDecimal(expr);
    }

    public BigDecimal calculateBigDecimal(String[] expr) throws IllegalOperandException {
        Stack numStk = new Stack<>();  //操作数栈
        Stack opStk = new Stack();  //操作符栈
        for (String s : expr) {
            if (isOperand(s)) {  //遇到数字,直接压栈
                BigDecimal num = new BigDecimal(s);
                numStk.push(num);
            } else if (s.equals("(")) {  //遇到左括号,直接压栈
                opStk.push(s);
            } else if (s.equals(")")) {
                while (true) {
                    String op = opStk.pop();
                    if (op.equals("("))  //弹出左括号,结束
                        break;
                    else {  //不是左括号,则为操作符,进行运算
                        BigDecimal right = numStk.pop();
                        BigDecimal left = numStk.pop();
                        BigDecimal re = operateBigDecimal(left, right, op);
                        numStk.push(re);
                    }
                }
            } else {  //+ - / *
                int priority = getPriority(s);//当前操作符优先级
                while (true) {
                    if (opStk.empty() || priority > getPriority(opStk.peek())) { //操作符栈为空 或 当前符号优先级比栈顶符号优先级高,直接入栈
                        opStk.push(s);
                        break;
                    } else {
                        BigDecimal right = numStk.pop();
                        BigDecimal left = numStk.pop();
                        String op = opStk.pop();
                        BigDecimal re = operateBigDecimal(left, right, op);
                        numStk.push(re);
                    }
                }
            }
        }
        while (!opStk.empty()) {  //对栈中剩余数进行运算
            BigDecimal right = numStk.pop();
            BigDecimal left = numStk.pop();
            String op = opStk.pop();
            BigDecimal re = operateBigDecimal(left, right, op);
            numStk.push(re);
        }
        return numStk.pop().setScale(scale, roundingMode);
    }


}

Exceptions.java

package my.Calculator;

public class Exceptions {
   public static class IllegalExpressionException extends Exception {
        public IllegalExpressionException() {
            super();
        }

    }

 public static    class IllegalOperandException extends Exception {
        public IllegalOperandException(String msg) {
            super(msg);
        }
    }
}

 

你可能感兴趣的:(小工具)