为了练习一下Java编程,今天写了一个能进行大数计算的类,只需要调用本类的一个方法,以算数表达式为参数,方法就可返回计算结果。
import java.math.BigInteger; import java.util.EmptyStackException; import java.util.HashMap; import java.util.Stack; /* * 该类实现对大值数进行简单计算的功能 * */ class BigNumCalculator { private String input; //要计算的表达式 private String output;//结算结果 Stack<BigInteger> operand;//操作数栈 Stack<String> operator;//操作符栈 HashMap<String, Integer> prect_map; //操作符和优先级之间的映射关系 /* * 无参构造函数 * */ public BigNumCalculator() { this.operand = new Stack<BigInteger>(); this.operator = new Stack<String>(); prect_map = new HashMap<String, Integer>(); prect_map.put("+", new Integer(1)); prect_map.put("-", new Integer(1)); prect_map.put("*", new Integer(2)); prect_map.put("/", new Integer(2)); } /* * 对输入的表达式进行简单的检查。合法字符:数字、+、-、*、/、(、)之外是否还包含别的字符) * 返回值:如果表达式不包含非合法字符,则返回true,否则返回false * 调用本类函数:无 * */ private void check()throws ExpressionException { if(!this.input.matches("[\\d\\+\\-\\*/()]*"))//用正则表达式检查表达式是否合法,如果不合法,抛出表达式不合法异常,不懂正则表达式的参考此处:点击打开链接 throw new ExpressionException("Expressions contain only numbers,+,-,*,/"); } /* * 函数功能:比较两个操作符的优先级 * 参数:要比较的两个操作符 * 返回值:如果1、第一个操作符优先级比第二个低,返回负值; * 2、优先级相同,返回0; * 3、第一个操作符比第二个操作符高,返回正值 * 调用本类函数:无 * */ private int compOperator(String op1, String op2) { return this.prect_map.get(op1).intValue() - this.prect_map.get(op2).intValue(); } /* * 函数功能:将两个指定的大数对象,按指定的操作符进行运算,得出结果 * 参数:要计算的两个大数类对象,和字符串表示的操作符 * 返回值:返回一个大整数类对象,表示操作结果 * 调用本类函数:无 * */ private BigInteger compute(BigInteger bi1, BigInteger bi2, String operator) { switch(operator.charAt(0)) { case ‘+‘: return bi1.add(bi2); case ‘-‘: return bi1.subtract(bi2); case ‘*‘: return bi1.multiply(bi2); case ‘/‘: return bi1.divide(bi2); default: return null; } } /* * 函数功能:根据输入的表达式,计算出用字符串表示的结果 * 参数:一个String对象,表示要计算的表达式 * 返回值:一个String对象,表示结算得到的结果 * 异常抛出:如果表达式不合法,则抛出相应的异常 * 调用本类中的函数:check(),compOperator(),compute() * */ public String calculate(String input) throws ExpressionException{ input = "(" + input + ")";//将传进来的表达式字符串赋值给类成员,之所以给表达式包上一层括号,上为了方便最后得到一个结果 this.input = input; this.check(); //检查表达式是否合法 StringBuffer sb = new StringBuffer(); //解析表达式时用来存储数字 for(int j = 0; j < input.length(); j ++) { String tmp = "" + input.charAt(j);//将当前正解析的字符转化为字符串 if(tmp.matches("\\d")) {//当前解析的是数字 sb.append(tmp.charAt(0)); } else if(tmp.charAt(0) == ‘(‘) {//当前解析的是‘(‘ //(前面必定紧挨着操作符,所以不需要将操作数进行压栈,因为StringBuffer对象必为空 this.operator.push(tmp); } else if(tmp.matches("[\\+\\-\\*/]{1}")) {//当前解析的是+、-、*、/ //遇到操作符,将之前的字符串变换为一个大数,压入操作数栈中,并将存储数字的StringBuffer对象清空 BigInteger biTemp = new BigInteger(sb.toString()); this.operand.push(biTemp); sb.delete(0, sb.length()); /*执行操作符栈中优先级低于或等于当前操作符的操作 * 首先从操作符栈中弹出一个操作符, * 然后从操作数栈中弹出两个操作数 * 执行操作后将结果压入操作数栈中 * */ while(!this.operator.empty()) { String topOperator = this.operator.pop(); if(topOperator.equals("(")) {//如果遇到"(",停止处理 this.operator.push(topOperator); break; } if(this.compOperator(tmp, topOperator) <= 0) {//如果栈中的操作符优先级比当前解析的操作符优先级高或相等 BigInteger bi1 = this.operand.pop(); BigInteger bi2 = this.operand.pop(); this.operand.push(this.compute(bi1, bi2, topOperator)); } else {//如果栈中的操作符比当前解析的操作符优先级低 this.operator.push(topOperator);//将弹出的操作符重新压入操作符栈 break; } } this.operator.push(tmp);//将当前操作符压入操作符栈 } else {//如果当前解析的右括号) //将之前的字符串变换为一个大数,压入操作数栈中,并将存储数字的StringBuffer对象清空 BigInteger biTemp = new BigInteger(sb.toString()); this.operand.push(biTemp); sb.delete(0, sb.length()); try { String topOperator = this.operator.pop(); while(!topOperator.equals("(")) { BigInteger bi1 = this.operand.pop(); BigInteger bi2 = this.operand.pop(); this.operand.push(this.compute(bi1, bi2, topOperator)); topOperator = this.operator.pop(); } } catch(EmptyStackException e) { throw new ExpressionException(); } } } if(!this.operator.empty() || this.operand.size() != 1) throw new ExpressionException(); this.output = this.operand.pop().toString(); return this.output; } }
上面的类中引用了自己编写的一个异常类:
/* * 自己编写的一个异常类,如果表达式不合法,则抛出该异常 * */ class ExpressionException extends Exception { /** * */ private static final long serialVersionUID = 1L; public ExpressionException(String msg) { super(msg); } public ExpressionException() { super("parsing fault"); } }