实现方法一 :截取字符串+递归
用double或float会出现精度丢失问题
1+2 * 3-6.6=0.4000001
2 * 3-6.6-6=5.4
-(3-6.5)=3.5
思路:例如像:1-2*3
划分表达式,先根据低级运算符,再根据高级运算符。当表达式中无运算符时,将表达式转换为可运算的类型。
1-2*3➜➜➜(exp1-exp2)➜➜➜(1-(exp3 * exp4))当exp中无符号时,转换为可运算的类型,➜➜➜(1 - (2 * 3))➜➜➜(1-6)➜➜➜-5
加入的( )表示优先顺序。。。
//考虑了+-/*()和负号,正号出现会出错
import java.math.BigDecimal;
public class Test {
public static void main(String[] args){
try{
String str = "1+2*3-6.6";
String str1 = "3-2*3-6.6";
String str2 = "3-(-(2*(3+6.5)))";
String str3 = "(-1)*(-1)+2";
String str4 =Math.PI+"+1";
String str5 ="-(-(1+2*3-6.6))+(3-2*3-6.6)+(3-(-(2*(3+6.5))))";
System.out.println(str+"="+opt(str));
System.out.println(str1+"="+opt(str1));
System.out.println(str2+"="+opt(str2));
System.out.println(str3+"="+opt(str3));
System.out.println(str4+"="+opt(str4).setScale(2,BigDecimal.ROUND_HALF_UP));
System.out.println(str5+"="+opt(str5));
}catch(Exception e){
e.printStackTrace();
}
}
public static BigDecimal opt(String s) throws Exception{
int a1=s.indexOf("+");
int a2=s.lastIndexOf("-");
int a3=s.indexOf("*");
int a4=s.indexOf("/");
int a5=s.indexOf("(");
if(a1==-1&&a2==-1&&a3==-1&&a4==-1){
return new BigDecimal(s.trim());
}
if(a5!=-1){
int a6=s.indexOf(")");
if(a6==-1){
throw new Exception("error");
}
else {
int flag=1;
a6=a5;
while(flag>0) {//加while循环可以处理多括号嵌套的,否则只能处理多括号不嵌套的
a6++;
if(s.charAt(a6)=='(') {
flag++;
}else if(s.charAt(a6)==')') {
flag--;
}
}
BigDecimal f=opt(s.substring(a5+1,a6).trim());
s=s.replace(s.substring(a5,a6+1), f.toString());
return opt(s);
}
}
if(a1!=-1){
return add(opt(s.substring(0,a1)),opt(s.substring(a1+1,s.length())));
}
if(a2!=-1){
if(s.indexOf("-")==0&&a2==s.indexOf("-")) {//处理像=-1的情况,避免=-1-2出错
return sub(BigDecimal.ZERO,opt(s.substring(a2+1,s.length())));
}else if(s.charAt(a2-1)=='-') { //处理像a--1的情况
if(s.indexOf("-")==0)
return sub(BigDecimal.ZERO,opt(s.substring(a2,s.length())));//处理像=--1的情况
return sub(opt(s.substring(0,a2-1)),opt(s.substring(a2,s.length())));
}
else if(s.charAt(a2-1)=='+') { //处理像a+-1的情况
return add(opt(s.substring(0,a2-1)),opt(s.substring(a2,s.length())));
}
else if(s.charAt(a2-1)=='*') {
return mul(opt(s.substring(0,a2-1)),opt(s.substring(a2,s.length())));
}
else if(s.charAt(a2-1)=='/') {
return div(opt(s.substring(0,a2-1)),opt(s.substring(a2,s.length())),2);
}else {
return sub(opt(s.substring(0,a2)),opt(s.substring(a2+1,s.length())));
}
}
if(a3!=-1){
return mul(opt(s.substring(0,a3)),opt(s.substring(a3+1,s.length())));
}
if(a4!=-1){
return div(opt(s.substring(0,a4)),opt(s.substring(a4+1,s.length())),32);
}
return new BigDecimal(s.trim());
}
public static BigDecimal add(BigDecimal a1, BigDecimal b1) {
BigDecimal a2 = new BigDecimal(a1.toString());
BigDecimal b2 = new BigDecimal(b1.toString());
return a2.add(b2);
}
public static BigDecimal sub(BigDecimal a1, BigDecimal b1) {
BigDecimal a2 = new BigDecimal(a1.toString());
BigDecimal b2 = new BigDecimal(b1.toString());
return a2.subtract(b2);
}
public static BigDecimal mul(BigDecimal a1, BigDecimal b1) {
BigDecimal a2 = new BigDecimal(a1.toString());
BigDecimal b2 = new BigDecimal(b1.toString());
return a2.multiply(b2);
}
public static BigDecimal div(BigDecimal a1, BigDecimal b1, int scale) {
if (scale < 0) {
throw new IllegalArgumentException("error");
}
BigDecimal a2 = new BigDecimal(a1.toString());
BigDecimal b2 = new BigDecimal(b1.toString());
return a2.divide(b2, scale, BigDecimal.ROUND_HALF_UP);
}
}
运算结果如下
1+2 * 3-6.6=0.4
3-2 * 3-6.6=-9.6
3-(-(2 * (3+6.5)))=22.0
(-1) * (-1)+2=3
3.141592653589793+1=4.14
-(-(1+2 * 3-6.6))+(3-2 * 3-6.6)+(3-(-(2 * (3+6.5))))=12.8
这种方法有很多问题,不好扩展,细节比较多。
实现方法二 后缀表达式
参考:https://blog.csdn.net/antineutrino/article/details/6763722
上面这个过程步骤写的细致,推荐
虽然用的是BigDecimal和double类型直接转换(我用的是BigDecimal类型计算,double类型作为中间类型存储),但还是有精度问题。比如无理数算的不准,超过16位算的不准的情况
如果是BigDecimal和String类型转换,可能情况会好一些,但没研究过。。
我增加了一些常见符号sincos的,若只想±*/()之类的,看上面链接。
package work;
import java.math.BigDecimal;
import java.util.Stack;
public class utilcal {
public static String calcultor(String input) {
Stack<Character> s1=new Stack<Character>();//符号栈(两个数运算的符号栈)
Stack<Double> s2=new Stack<Double>();//数字栈
Stack<Object> expression = new Stack<Object>();//表达式
double number=0;//转存数字||也用于装配方法的参数,不参与计算
char tempChar;//转存字符
for (int i = 0; i < input.length(); i++) {
char c = input.charAt(i);
//读取简单运算直接存栈
if (c=='π'||c=='e') {
if (c=='e') {
s2.push( Math.E);
expression.push('e');
}if (c=='π') {
s2.push( Math.PI);
expression.push('π');
}
}
//读取数(包括正负数和小数)进数字栈
else if(Character.isDigit(c)||c=='.'||(input.charAt(0)=='-'&&i==0)||(i!=0&&isAllOperator(input.charAt(i-1))&&c=='-')
||(input.charAt(0)=='+'&&i==0)||(i!=0&&isAllOperator(input.charAt(i-1))&&c=='+')) {
int lastindex = readnumber(input,i);
expression.push(input.substring(i, lastindex));
number =Double.parseDouble(input.substring(i, lastindex));
i=lastindex-1;
s2.push( number);
}else if(isOperator(c)||c=='c'||c=='s'||c=='t'||c=='r'||c=='l'||c=='√'||c=='^'||c=='!'||c=='%') {
/*
*符号栈为空或栈顶运算符为左括号“(”,直接入栈
*若优先级比栈顶运算符的高,直接入栈
*
*否则,将符号栈顶的运算符弹出并压入到表达式栈中,再入栈
*/
while (!s1.isEmpty()
&& s1.peek() != '('
&& priorityCompare(c, s1.peek()) <= 0) {
if (s1.peek()=='c'||s1.peek()=='s'||s1.peek()=='t'||s1.peek()=='r'||s1.peek()=='l'||s1.peek()=='√'||s1.peek()=='!'||s1.peek()=='%') {
if (s1.peek()=='!') {
if(!(s2.peek()==s2.peek().intValue())) {
int k=1/0;
}else {
s2.push((double) doFactorial(s2.pop().intValue()));
s1.pop();
expression.push('!');
}
}else if(s1.peek()=='%'){
s2.push( div(s2.pop(), 100));
s1.pop();
expression.push('%');
}else {
double num2=s2.pop();
s2.push(calc(number, num2, s1.pop()));
}
}else {
expression.push(s1.peek());
// System.out.println(s1.peek());
double num1 = s2.pop();
double num2 = s2.pop();
s2.push(calc(num2, num1, s1.pop()));
}
//读取复杂运算存栈,类似cos/sin....
}if (c=='c'||c=='s'||c=='t'||c=='r'||c=='l'||c=='√'||c=='^') {
int lastindex = readotherChar(input,i);
if ("sin".equals(input.substring(i, lastindex))) {
s1.push('s');
expression.push("sin");
}else if ("cos".equals(input.substring(i, lastindex))) {
s1.push('c');
expression.push("cos");
}else if ("tan".equals(input.substring(i, lastindex))) {
s1.push('t');
expression.push("tan");
}else if ("log".equals(input.substring(i, lastindex))) {
s1.push('l');
expression.push("log");
}else if ("ln".equals(input.substring(i, lastindex))) {
s1.push('r');
expression.push("ln");
}else if ("√".equals(input.substring(i, lastindex))) {
s1.push('√');
expression.push("√");
}else if ("^".equals(input.substring(i, lastindex))) {
s1.push('^');
}
i=lastindex-1;
}else {
s1.push(c);
}
}else if(c == '(') {
/*
* 如果是左括号“(”,则直接压入S1;
*/
s1.push(c);
}else if (c == ')') {
/*
* 如果是右括号“)”,则依次弹出符号栈顶的运算符,并压入表达式栈
*/
while ((tempChar=s1.peek()) != '(') {
if (s1.peek()=='c'||s1.peek()=='s'||s1.peek()=='t'||s1.peek()=='r'||s1.peek()=='l'||s1.peek()=='√'||s1.peek()=='!'||s1.peek()=='%') {
if (s1.peek()=='!') {
if(!(s2.peek()==s2.peek().intValue())) {
int k=1/0;
}else {
s2.push((double) doFactorial(s2.pop().intValue()));
s1.pop();
expression.push('!');
}
}else if(s1.peek()=='%'){
s2.push( div(s2.pop(), 100));
s1.pop();
expression.push('%');
}else {
double num2=s2.pop();
s2.push(calc(number, num2, s1.pop()));
}
}else {
expression.push(tempChar);
// System.out.println(s1.peek());
double num1 = s2.pop();
double num2 = s2.pop();
s2.push(calc(num2, num1, s1.pop()));
}
}
if (s1.peek()=='(') {
s1.pop();
}
}
}
/**
* 后缀表达式
*/
int size=0 ;
System.out.print("后缀表达式:");
while (size<expression.size()) {
System.out.print( expression.get(size)+" ");
size++;
}
size = s1.size();
char c;
while(size>0){
size--;
c = s1.get(size);
if (c=='√'||c=='c'||c=='t'||c=='s'||c=='l'||c=='!'||c=='%'||c=='√') {//已经存了,不用再打印
}else {
System.out.print( s1.get(size)+" ");
}
}
/**
* 结果
*/
while (!s1.isEmpty()) {
if (s1.peek()=='c'||s1.peek()=='s'||s1.peek()=='t'||s1.peek()=='r'||s1.peek()=='l'||s1.peek()=='√'||s1.peek()=='!'||s1.peek()=='%') {
if (s1.peek()=='!') {
if(!(s2.peek()==s2.peek().intValue())) {
int k=1/0;
}else {
s2.push((double) doFactorial(s2.pop().intValue()));
s1.pop();
expression.push('!');
}
}else if(s1.peek()=='%'){
s2.push( div(s2.pop(), 100));
s1.pop();
}else {
double num2=s2.pop();
s2.push(calc(number, num2, s1.pop()));
}
}else {
tempChar = s1.pop();
double num1 = s2.pop();
double num2 = s2.pop();
s2.push(calc(num2, num1, tempChar));
}
}
double result=s2.pop();
result = round(result);
System.out.println("\n结果:"+check(result));
System.out.println("-----------------------------------------");
return check(result).toString();
}
private static int readnumber(String input, int start) {
int len = input.length();
boolean flag=true;
int i = 0;
char c;
for (i = start; i < len; i++) {
c = input.charAt(i);
if((Character.isDigit(c))||(c=='.')||((c=='-'||c=='+')&&flag)) {
flag=false;
}else {
return i;
}
}
return i;
}
/**
* 读取符号如sin/cos/tan/log/ln
* @param c
* @return
*/
private static int readotherChar(String input, int start) {
// TODO Auto-generated method stub
int i = 0;
char c;
for (i = start; i < input.length(); i++) {
c = input.charAt(i);
if(c=='c'||c=='s'||c=='t') {
return i=i+3;
}else if(c=='l'&&input.charAt(i+1)=='n'){
return i=i+2;
}else if(c=='l'&&input.charAt(i+1)=='o'&&input.charAt(i+2)=='g'){
return i=i+3;
}else if (c=='√'||c=='^') {
return i=i+1;
}
}
return i;
}
private static boolean isOperator(char c) {
return (c=='+' || c=='-' || c=='*' || c=='/');
}
private static boolean isAllOperator(char c) {
return (c=='+' || c=='-' || c=='*' || c=='/' || c =='(' || c =='^');
}
/**
*符号对应关系
* {
* + : +
* - : -
* * : *
* / : /
* ^ : ^
* √ : √
* ! : !
*
* s : sin
* c : cos
* t : tan
* l : log
* r : ln
* }
* @return
* @throws IllegalArgumentException
*/
private static double calc(double num1, double num2, char op)
throws IllegalArgumentException {
switch (op) {
case '+':
return add(num1,num2);
case '-':
return sub(num1,num2);
case '*':
return mul(num1,num2);
case '/':
if (num2 == 0) throw new IllegalArgumentException("divisor can't be 0.");
return div(num1,num2);
case '^':
return Math.pow(num1,num2);
case '√':
return Math.sqrt(num2);
case 's':
return Math.sin(mul(div(num2,180.0), Math.PI));
case 'c':
return Math.cos(mul(div(num2,180.0), Math.PI));
case 't':
return Math.tan(mul(div(num2,180.0), Math.PI));
case 'l':
return Math.log10(num2);
case 'r':
return Math.log(num2);
default:
return 0;
}
}
private static int priorityCompare(char op1, char op2) {
switch (op1) {
/**
* 1 : 相比较高优先级
* 0 :相比相同优先级
* -1 :相比较低优先级
*/
//最低优先级
case '+': case '-':
return (op2 == '*' || op2 == '/' || op2 == 's' || op2 == 'c' || op2 == 't'
|| op2 == 'l' || op2 == 'r' || op2 == '√' || op2 == '^' || op2 == '!' || op2 == '%'? -1 : 0);
//中间优先级
case '*': case '/':
if (op2 == '+' || op2 == '-') {
return 1;
}else if (op2 == '*' || op2 == '/') {
return 0;
}else {
return -1;
}
case '!': case '%':
if (op2 == '+' || op2 == '-'||op2 == '*' || op2 == '/'|| op2 == '^') {
return 1;
}else if (op2 == '!' || op2 == '%' ){
return 0;
}else {
return -1;
}
//最高优先级
case 's': case 'c': case 't': case 'l': case 'r': case '√': case '^':
return (op2 == '+' || op2 == '-' || op2 == '*' || op2 == '/' ? 1 : 0);
}
return 1;
}
/**
* 求阶乘
*/
public static double doFactorial(int n){
if(n<0){
return -1;//传入的数据不合法
}
if(n==0){
return 1;
}else if(n==1){//递归结束的条件
return 1;
}else{
return mul(n,doFactorial(n-1));
}
}
/**
* 精度计算
*/
public static double add(double v1, double v2) {
BigDecimal b1 = new BigDecimal(Double.toString(v1));
BigDecimal b2 = new BigDecimal(Double.toString(v2));
return b1.add(b2).doubleValue();
}
public static double sub(double v1, double v2) {
BigDecimal b1 = new BigDecimal(Double.toString(v1));
BigDecimal b2 = new BigDecimal(Double.toString(v2));
return b1.subtract(b2).doubleValue();
}
public static double mul(double v1, double v2) {
BigDecimal b1 = new BigDecimal(Double.toString(v1));
BigDecimal b2 = new BigDecimal(Double.toString(v2));
return b1.multiply(b2).doubleValue();
}
public static double div(double v1, double v2) {
BigDecimal b1 = new BigDecimal(Double.toString(v1));
BigDecimal b2 = new BigDecimal(Double.toString(v2));
return b1.divide(b2, 16, BigDecimal.ROUND_HALF_UP).doubleValue();
}
public static double round(double v) {
BigDecimal b = new BigDecimal(Double.toString(v));
return b.setScale(15, BigDecimal.ROUND_HALF_UP).doubleValue();
}
/**
* 检查结果格式
*/
public static Object check(double result) {
if ((int)result==result) {
return (int)result;
}
return result;
}
}