java计算器 BigDecimal解决精度问题

实现方法一 :截取字符串+递归

用double或float会出现精度丢失问题
1+2 * 3-6.6=0.4000001
2 * 3-6.6-6=5.4
-(3-6.5)=3.5

JAVA中double类型运算结果异常的解决

BigDecimal加减乘除计算

思路:例如像: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;
          }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值