Java計算數(shù)學表達式代碼詳解
Java字符串轉(zhuǎn)換成算術(shù)表達式計算并輸出結(jié)果,通過這個工具可以直接對字符串形式的算術(shù)表達式進行運算,并且使用非常簡單。
這個工具中包含兩個類 Calculator 和 ArithHelper
Calculator 代碼如下:
import java.util.Collections;
import java.util.Stack;
/**
* 算數(shù)表達式求值
* 直接調(diào)用Calculator的類方法conversion()
* 傳入算數(shù)表達式,將返回一個浮點值結(jié)果
* 如果計算過程錯誤,將返回一個NaN
*/
public class Calculator {
private Stack<String> postfixStack = new Stack<String>();
// 后綴式棧
private Stack<Character> opStack = new Stack<Character>();
// 運算符棧
private int[] operatPriority = new int[] { 0, 3, 2, 1, -1, 1, 0, 2 };
// 運用運算符ASCII碼-40做索引的運算符優(yōu)先級
public static double conversion(String expression) {
double result = 0;
Calculator cal = new Calculator();
try {
expression = transform(expression);
result = cal.calculate(expression);
}
catch (Exception e) {
// e.printStackTrace();
// 運算錯誤返回NaN
return 0.0 / 0.0;
}
// return new String().valueOf(result);
return result;
}
/**
* 將表達式中負數(shù)的符號更改
*
* @param expression
* 例如-2+-1*(-3E-2)-(-1) 被轉(zhuǎn)為 ~2+~1*(~3E~2)-(~1)
* @return
*/
private static String transform(String expression) {
char[] arr = expression.toCharArray();
for (int i = 0; i < arr.length; i++) {
if (arr[i] == '-') {
if (i == 0) {
arr[i] = '~';
} else {
char c = arr[i - 1];
if (c == '+' || c == '-' || c == '*' || c == '/' || c == '(' || c == 'E' || c == 'e') {
arr[i] = '~';
}
}
}
}
if(arr[0]=='~'||arr[1]=='('){
arr[0]='-';
return "0"+new String(arr);
} else{
return new String(arr);
}
}
/**
* 按照給定的表達式計算
*
* @param expression
* 要計算的表達式例如:5+12*(3+5)/7
* @return
*/
public double calculate(String expression) {
Stack<String> resultStack = new Stack<String>();
prepare(expression);
Collections.reverse(postfixStack);
// 將后綴式棧反轉(zhuǎn)
String firstValue, secondValue, currentValue;
// 參與計算的第一個值,第二個值和算術(shù)運算符
while (!postfixStack.isEmpty()) {
currentValue = postfixStack.pop();
if (!isOperator(currentValue.charAt(0))) {
// 如果不是運算符則存入操作數(shù)棧中
currentValue = currentValue.replace("~", "-");
resultStack.push(currentValue);
} else {
// 如果是運算符則從操作數(shù)棧中取兩個值和該數(shù)值一起參與運算
secondValue = resultStack.pop();
firstValue = resultStack.pop();
// 將負數(shù)標記符改為負號
firstValue = firstValue.replace("~", "-");
secondValue = secondValue.replace("~", "-");
String tempResult = calculate(firstValue, secondValue, currentValue.charAt(0));
resultStack.push(tempResult);
}
}
return double.valueOf(resultStack.pop());
}
/**
* 數(shù)據(jù)準備階段將表達式轉(zhuǎn)換成為后綴式棧
*
* @param expression
*/
private void prepare(String expression) {
opStack.push(',');
// 運算符放入棧底元素逗號,此符號優(yōu)先級最低
char[] arr = expression.toCharArray();
int currentIndex = 0;
// 當前字符的位置
int count = 0;
// 上次算術(shù)運算符到本次算術(shù)運算符的字符的長度便于或者之間的數(shù)值
char currentOp, peekOp;
// 當前操作符和棧頂操作符
for (int i = 0; i < arr.length; i++) {
currentOp = arr[i];
if (isOperator(currentOp)) {
// 如果當前字符是運算符
if (count > 0) {
postfixStack.push(new String(arr, currentIndex, count));
// 取兩個運算符之間的數(shù)字
}
peekOp = opStack.peek();
if (currentOp == ')') {
// 遇到反括號則將運算符棧中的元素移除到后綴式棧中直到遇到左括號
while (opStack.peek() != '(') {
postfixStack.push(String.valueOf(opStack.pop()));
}
opStack.pop();
} else {
while (currentOp != '(' && peekOp != ',' && compare(currentOp, peekOp)) {
postfixStack.push(String.valueOf(opStack.pop()));
peekOp = opStack.peek();
}
opStack.push(currentOp);
}
count = 0;
currentIndex = i + 1;
} else {
count++;
}
}
if (count > 1 || (count == 1 && !isOperator(arr[currentIndex]))) {
// 最后一個字符不是括號或者其他運算符的則加入后綴式棧中
postfixStack.push(new String(arr, currentIndex, count));
}
while (opStack.peek() != ',') {
postfixStack.push(String.valueOf(opStack.pop()));
// 將操作符棧中的剩余的元素添加到后綴式棧中
}
}
/**
* 判斷是否為算術(shù)符號
*
* @param c
* @return
*/
private Boolean isOperator(char c) {
return c == '+' || c == '-' || c == '*' || c == '/' || c == '(' || c == ')';
}
/**
* 利用ASCII碼-40做下標去算術(shù)符號優(yōu)先級
*
* @param cur
* @param peek
* @return
*/
public Boolean compare(char cur, char peek) {
// 如果是peek優(yōu)先級高于cur,返回true,默認都是peek優(yōu)先級要低
Boolean result = false;
if (operatPriority[(peek) - 40] >= operatPriority[(cur) - 40]) {
result = true;
}
return result;
}
/**
* 按照給定的算術(shù)運算符做計算
*
* @param firstValue
* @param secondValue
* @param currentOp
* @return
*/
private String calculate(String firstValue, String secondValue, char currentOp) {
String result = "";
switch (currentOp) {
case '+':
result = String.valueOf(ArithHelper.add(firstValue, secondValue));
break;
case '-':
result = String.valueOf(ArithHelper.sub(firstValue, secondValue));
break;
case '*':
result = String.valueOf(ArithHelper.mul(firstValue, secondValue));
break;
case '/':
result = String.valueOf(ArithHelper.div(firstValue, secondValue));
break;
}
return result;
}
}
ArithHelper 代碼如下:
public class ArithHelper {
// 默認除法運算精度
private static final int DEF_DIV_SCALE = 16;
// 這個類不能實例化
private ArithHelper() {
}
/**
* 提供精確的加法運算。
*
* @param v1 被加數(shù)
* @param v2 加數(shù)
* @return 兩個參數(shù)的和
*/
public static double add(double v1, double v2) {
java.math.BigDecimal b1 = new java.math.BigDecimal(double.toString(v1));
java.math.BigDecimal b2 = new java.math.BigDecimal(double.toString(v2));
return b1.add(b2).doubleValue();
}
public static double add(String v1, String v2) {
java.math.BigDecimal b1 = new java.math.BigDecimal(v1);
java.math.BigDecimal b2 = new java.math.BigDecimal(v2);
return b1.add(b2).doubleValue();
}
/**
* 提供精確的減法運算。
*
* @param v1 被減數(shù)
* @param v2 減數(shù)
* @return 兩個參數(shù)的差
*/
public static double sub(double v1, double v2) {
java.math.BigDecimal b1 = new java.math.BigDecimal(double.toString(v1));
java.math.BigDecimal b2 = new java.math.BigDecimal(double.toString(v2));
return b1.subtract(b2).doubleValue();
}
public static double sub(String v1, String v2) {
java.math.BigDecimal b1 = new java.math.BigDecimal(v1);
java.math.BigDecimal b2 = new java.math.BigDecimal(v2);
return b1.subtract(b2).doubleValue();
}
/**
* 提供精確的乘法運算。
*
* @param v1
* 被乘數(shù)
* @param v2
* 乘數(shù)
* @return 兩個參數(shù)的積
*/
public static double mul(double v1, double v2) {
java.math.BigDecimal b1 = new java.math.BigDecimal(double.toString(v1));
java.math.BigDecimal b2 = new java.math.BigDecimal(double.toString(v2));
return b1.multiply(b2).doubleValue();
}
public static double mul(String v1, String v2) {
java.math.BigDecimal b1 = new java.math.BigDecimal(v1);
java.math.BigDecimal b2 = new java.math.BigDecimal(v2);
return b1.multiply(b2).doubleValue();
}
/**
* 提供(相對)精確的除法運算,當發(fā)生除不盡的情況時,精確到 小數(shù)點以后10位,以后的數(shù)字四舍五入。
*
* @param v1
* 被除數(shù)
* @param v2
* 除數(shù)
* @return 兩個參數(shù)的商
*/
public static double div(double v1, double v2) {
return div(v1, v2, DEF_DIV_SCALE);
}
public static double div(String v1, String v2) {
java.math.BigDecimal b1 = new java.math.BigDecimal(v1);
java.math.BigDecimal b2 = new java.math.BigDecimal(v2);
return b1.divide(b2, DEF_DIV_SCALE, java.math.BigDecimal.ROUND_HALF_UP).doubleValue();
}
/**
* 提供(相對)精確的除法運算。當發(fā)生除不盡的情況時,由scale參數(shù)指 定精度,以后的數(shù)字四舍五入。
*
* @param v1 被除數(shù)
* @param v2 除數(shù)
* @param scale 表示表示需要精確到小數(shù)點以后幾位。
* @return 兩個參數(shù)的商
*/
public static double div(double v1, double v2, int scale) {
if (scale < 0) {
throw new IllegalArgumentException("The scale must be a positive integer or zero");
}
java.math.BigDecimal b1 = new java.math.BigDecimal(double.toString(v1));
java.math.BigDecimal b2 = new java.math.BigDecimal(double.toString(v2));
return b1.divide(b2, scale, java.math.BigDecimal.ROUND_HALF_UP).doubleValue();
}
/**
* 提供精確的小數(shù)位四舍五入處理。
*
* @param v 需要四舍五入的數(shù)字
* @param scale 小數(shù)點后保留幾位
* @return 四舍五入后的結(jié)果
*/
public static double round(double v, int scale) {
if (scale < 0) {
throw new IllegalArgumentException("The scale must be a positive integer or zero");
}
java.math.BigDecimal b = new java.math.BigDecimal(double.toString(v));
java.math.BigDecimal one = new java.math.BigDecimal("1");
return b.divide(one, scale, java.math.BigDecimal.ROUND_HALF_UP).doubleValue();
}
public static double round(String v, int scale) {
if (scale < 0) {
throw new IllegalArgumentException("The scale must be a positive integer or zero");
}
java.math.BigDecimal b = new java.math.BigDecimal(v);
java.math.BigDecimal one = new java.math.BigDecimal("1");
return b.divide(one, scale, java.math.BigDecimal.ROUND_HALF_UP).doubleValue();
}
}
使用時調(diào)用 Calculator 類的 conversion()方法,并傳入算術(shù)表達式參數(shù),即可返回一個 Double 類型的值。
使用示例:
public class MathTest {
public static void main(String[] args) {
String expression = "(0*1--3)-5/-4-(3*(-2.13))";
double result = Calculator.conversion(expression);
System.out.println(expression + " = " + result);
System.out.println();
}
}
控制臺輸出:
(0*1--3)-5/-4-(3*(-2.13)) = 10.64
測試截圖:

總結(jié)
以上就是本文關(guān)于Java計算數(shù)學表達式代碼詳解的全部內(nèi)容,希望對大家有所幫助。感興趣的朋友可以繼續(xù)參閱本站其他相關(guān)專題,如有不足之處,歡迎留言指出。感謝朋友們對本站的支持!
相關(guān)文章
SpringBoot/Spring?AOP默認動態(tài)代理方式實例詳解
這篇文章主要給大家介紹了關(guān)于SpringBoot/Spring?AOP默認動態(tài)代理方式的相關(guān)資料,Spring AOP是一款基于Java的AOP框架,其中默認采用動態(tài)代理方式實現(xiàn)AOP功能,本文將詳細介紹動態(tài)代理的實現(xiàn)原理和使用方法,需要的朋友可以參考下2023-03-03
Spring Junit測試找不到SpringJUnit4ClassRunner.class的解決
這篇文章主要介紹了Spring Junit測試找不到SpringJUnit4ClassRunner.class的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-04-04
微信公眾號開發(fā)之設(shè)置自定義菜單實例代碼【java版】
這篇文章主要介紹了微信公眾號開發(fā)之設(shè)置自定義菜單實例代碼,本實例是為了實現(xiàn)在管理后臺實現(xiàn)微信菜單的添加刪除管理。需要的朋友可以參考下2018-06-06

