包含简单科学运算的表达式求值
2016-12-12 11:37
453 查看
包含简单科学运算的表达式求值
想写个计算器,但又没有在网上找到直接可用的开源代码,于是自己试着捣鼓一下,写了这个工具类。源代码
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 = calcul d0c4 ator.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"; } } }
相关文章推荐
- 简单表达式求值的C++代码(10以内不包含括号的加减乘除)
- 数据结构之简单四则运算表达式求值8-(栈的实现)
- 输入一个只包含个位数字的简单四则运算表达式字符串,计算该表达式的值
- 简单表达式求值(用栈实现)
- 最简单的表达式求值
- 四则运算表达式求值(栈的应用)
- 简单表达式求值
- 简单表达式求值——算符优先法
- 使用传统算法进行表达式求值(数字支持科学表示法,操作符支持加减乘除乘方, 支持括号, 不支持函数)
- 后缀表达式 求值运算 javascript版
- 中缀表达式的计算(只包含四则运算与括号)
- C++ 四则运算表达式(简单的+-*/带括号) 栈
- Linux系统下用C语言实现浮点数四则运算表达式的求值
- 表达式运算顺序与求值顺序,副作用操作符(++,--),序列点
- 实现简单的表达式求值
- 四则运算表达式求值
- 二叉树显示(图形界面,控制台字符),简单表达式求值,pyqt,swig初试....
- 支持算术运算、逻辑运算、位运算的表达式求值
- 用栈实现 表达式求值的运算源码
- 一个简单的运算表达式解释器例子