Java高精度四则运算(无括号限制)


Java高精度四则运算(无括号限制)

package cn.skyatom.common;
 
import java.math.BigDecimal;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
 
/**
 * 基础四则运算
 *
 * @author ZWK
 */
public class Arithmetic {
 
    private static String getUUID() {
        return java.util.UUID.randomUUID().toString().replaceAll("-", "");
    }
 
    public static void main(String[] args) throws Exception {
        java.util.Map<String, BigDecimal> values = new java.util.HashMap<String, BigDecimal>();
        BigDecimal AAF = new BigDecimal(5.5);
        BigDecimal BCCC = new BigDecimal(8);
        BigDecimal QQC = new BigDecimal(-8.33);
        BigDecimal DCC = new BigDecimal(2);
        BigDecimal EE = new BigDecimal(23);
        BigDecimal BF = new BigDecimal(2.5);
        BigDecimal A1 = new BigDecimal(12);
        BigDecimal A2 = new BigDecimal(4);
        BigDecimal A3 = new BigDecimal(5);
        BigDecimal A4 = new BigDecimal(15);
 
        values.put("AAF", AAF);
        values.put("BCCC", BCCC);
        values.put("QQC", QQC);
        values.put("DCC", DCC);
        values.put("EE", EE);
        values.put("BF", BF);
        values.put("A1", A1);
        values.put("A2", A2);
        values.put("A3", A3);
        values.put("A4", A4);
 
//       
//        values.put("B1", 4F);
//        values.put("B2", 15f);
//        values.put("B3", 55f);
//        values.put("B4", 2f);
//        values.put("B5", 5f);
        String str = "AAF  * BCCC + QQC  /DCC-EE*BF+( A1*(A2/(A3+A4))  ) ";//5.5*8 + (-8.33)/2 - 23*2.5 + (12*(4/(5+15)) )
        //String str = "B1  * B2 + B3 -B4/  B5 ";//去空白
        //BigDecimal v = getArithmeticValue(str, values);
        System.out.println("结果为:" + getArithmeticFloatValue(str, values));
    }
 
    /**
    * 执行运算,获取表达式的结果。float值
    *
    * @param str
    * @param values
    * @return
    * @throws Exception
    */
    public static float getArithmeticFloatValue(String str, java.util.Map<String, BigDecimal> values) throws Exception {
        return getArithmeticValue(str, values).floatValue();
    }
 
    public static int getArithmeticIntValue(String str, java.util.Map<String, BigDecimal> values) throws Exception {
        return getArithmeticValue(str, values).intValue();
    }
 
    public static long getArithmeticLongValue(String str, java.util.Map<String, BigDecimal> values) throws Exception {
        return getArithmeticValue(str, values).longValue();
    }
 
    /**
    * 替换括号
    *
    * @param str
    * @param values
    * @return 当所有替换完成,null,反之返回替换的字符串
    */
    private static String replaceBrackets(String str, java.util.Map<String, BigDecimal> values) {
        String v = "";
        String tmp = null;//临时字符串值
        Pattern patt = Pattern.compile("\\(([A-Za-z0-9\\.\\*\\+\\-/]*?)\\)", Pattern.DOTALL);
        Matcher mat = patt.matcher(str);
        if (mat.find()) {
            tmp = mat.group(1);
        }
        if (tmp != null) {
            String uuid = getUUID();
            BigDecimal value = getBasicArithmeticValue(tmp, values);
            str = str.replace("(" + tmp + ")", uuid);
            values.put(uuid, value);
            v = str;
            v = replaceBrackets(v, values);
        } else {
            v = str;
        }
        return v;
    }
 
    /**
    * 执行运算,获取表达式的结果
    *
    * @param str 表达式字符串
    * @param values 值存储表
    * @return 返回运算值
    * @throws java.lang.Exception 运算格式错误时,抛出异常
    */
    public static BigDecimal getArithmeticValue(String str, java.util.Map<String, BigDecimal> values) throws Exception {
        str = str.replaceAll("\\s*", "");//去空白
        String s = replaceBrackets(str, values);
        if (s != null || !s.trim().equals("")) {
            str = s;
        }
        return getBasicArithmeticValue(str, values);
    }
 
    /**
    * 基本四则运算
    *
    * @param str 基础四则运算
    * @param values 值存储表
    * @return
    */
    private static BigDecimal getBasicArithmeticValue(String str, java.util.Map<String, BigDecimal> values) {
        str = multiReg(str, values);
        str = divReg(str, values);
        java.util.List<Boolean> signs = getPlusReduceSign(str);//获取符号
        java.util.List<String> valuesign = getValueSign(str);//替换符号
        BigDecimal v = getValue(valuesign, signs, values);
        return v;
    }
 
    /**
    * 获取结果
    *
    * @param valuesign 值替换符号
    * @param signs 符号
    * @param values 值存储表
    * @return
    */
    private static BigDecimal getValue(java.util.List<String> valuesign, java.util.List<Boolean> signs, java.util.Map<String, BigDecimal> values) {
        BigDecimal value = values.get(valuesign.get(0));
        for (int i = 0; i < signs.size(); i++) {
            if (signs.get(i)) {
                value = value.add(values.get(valuesign.get(i + 1)));
                //value += values.get(valuesign.get(i + 1));
            } else {
                value = value.subtract(values.get(valuesign.get(i + 1)));
                //value -= values.get(valuesign.get(i + 1));
            }
        }
        return value;
    }
 
    /**
    * 获取替换的符号
    *
    * @param str 待匹配的字符串
    * @return 返回 替换的值符号
    */
    private static java.util.List<String> getValueSign(String str) {
        java.util.List<String> list = new java.util.ArrayList<String>();
        Pattern patt = Pattern.compile("([a-zA-Z0-9]*{1})", Pattern.DOTALL);
        Matcher mat = patt.matcher(str);
        while (mat.find()) {
            if (mat.group(1).trim().equals("")) {
                continue;
            }
            list.add(mat.group(1));
        }
        return list;
    }
 
    /**
    * 获取加减符号
    *
    * @param str 待匹配的字符串
    * @return 返回 符号顺序,加号为true,减号为false
    */
    private static java.util.List<Boolean> getPlusReduceSign(String str) {
        java.util.List<Boolean> list = new java.util.ArrayList<Boolean>();
        Pattern patt = Pattern.compile("([a-zA-Z0-9]*{1}([+|-])[a-zA-Z0-9]*{1})", Pattern.DOTALL);
        Matcher mat = patt.matcher(str);
        while (mat.find()) {
            if (mat.group(2).trim().equals("+")) {
                list.add(true);
            } else {
                list.add(false);
            }
        }
        return list;
    }
 
    /**
    * 乘法的正则
    *
    * @param str 运算表达式字符串
    * @param values 值存储表
    * @return 返回重构后的字符串
    */
    private static String multiReg(String str, java.util.Map<String, BigDecimal> values) {
        Pattern patt = Pattern.compile("([a-zA-Z0-9]*{1}\\*[a-zA-Z0-9]*{1})", Pattern.DOTALL);
        Matcher mat = patt.matcher(str);
        while (mat.find()) {
            str = excMultiplication(str, mat.group(1), values);
        }
        return str;
    }
 
    /**
    * 除法的正则
    *
    * @param str 运算表达式字符串
    * @param values 值存储表
    * @return 返回重构后的字符串
    */
    private static String divReg(String str, java.util.Map<String, BigDecimal> values) {
        Pattern patt = Pattern.compile("([a-zA-Z0-9]*{1}\\/[a-zA-Z0-9]*{1})", Pattern.DOTALL);
        Matcher mat = patt.matcher(str);
        while (mat.find()) {
            str = excDivsion(str, mat.group(1), values);
        }
        return str;
    }
 
    /**
    * 计算乘法
    *
    * @param str 全部的运算字符串
    * @param value 计算乘法的字符串
    * @param map 值存储表
    * @return 返回重构后的字符串
    */
    private static String excMultiplication(String str, String value, java.util.Map<String, BigDecimal> map) {
        String vs[] = value.split("\\*");
        BigDecimal v1 = map.get(vs[0]);
        BigDecimal v2 = map.get(vs[1]);
        BigDecimal x = v1.multiply(v2);
        map.remove(vs[0]);
        map.remove(vs[1]);
        String uuid = getUUID();
        map.put(uuid, x);
        str = str.replace(value, uuid);
        return str;
    }
 
    /**
    * 计算出发
    *
    * @param str 全部的运算字符串
    * @param value 计算乘法的字符串
    * @param map 值存储表
    * @return 返回重构后的字符串
    */
    private static String excDivsion(String str, String value, java.util.Map<String, BigDecimal> map) {
        String vs[] = value.split("\\/");
        BigDecimal v1 = map.get(vs[0]);
        BigDecimal v2 = map.get(vs[1]);
        BigDecimal x = v1.divide(v2);
        map.remove(vs[0]);
        map.remove(vs[1]);
        String uuid = getUUID();
        map.put(uuid, x);
        str = str.replace(value, uuid);
        return str;
    }
}

最近在开发公司的绩效系统,老板又很抠门,不想购买市面上的绩效系统。。于是乎,苦逼的我又开始了苦逼的编程……

系统里面涉及到报表,而各员工间的绩效以及实发工资的算法每隔一段时间就会更新,所以不可能做到将算法写进源码编译,需要报表公式进行计算(当然,报表公式系统需要另行开发,这里不描述)。

以上是JAVA代码,其思想是将公式字中的参数当作字符串来看待,并不是当作纯粹的数字。每次运算时,只进行二元运算,运算之后将数据保存,再删除原数据表中的数据。如此循环,无需考虑括号的限制了。

在实现代码时,考虑了直接使用float或者是double类型,但是在最终显示结果是,两个类型精度都会产生精度上的丢失,所以最终考虑使用BigDecimal类型,也算是做长期运行考虑吧。

其中有很多需要优化的地方,敢兴趣的朋友可以留言交流……

本文永久更新链接地址

相关内容

    暂无相关文章