您的位置:首页 > 编程语言 > Java开发

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

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";
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java