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类型,也算是做长期运行考虑吧。

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

时间: 2024-10-06 21:14:59

Java高精度四则运算(无括号限制)的相关文章

栈的应用 -- 无括号表达式的求值

package com.learn.algorithm.expression; import java.util.HashMap; import java.util.Map; import java.util.Stack; /** * 无括号表达式求值 * @author Jiekun.Cui * */ public class Expression { /** * 操作符的优先级定义 */ public static Map<String,Integer> optProirity = nul

Java高精度学习第二弹——求N!

继续学习Java高精度,今天写的是求N!. 首先附上源代码: import java.util.Scanner; import java.math.BigInteger; public class Main { public static void main(String []args) { Scanner cin = new Scanner(System.in); BigInteger a,n,i; while(cin.hasNext()) { a = cin.nextBigInteger()

java byte转无符号int

import java.io.ByteArrayInputStream; public class Test{ public static void main(String[] args) { byte[] bytes = new byte[]{(byte)-42}; ByteArrayInputStream in = new ByteArrayInputStream(bytes); int result = in.read(); System.out.println("无符号数: \t&quo

Activit最入门学习文档,从如何创建项目开始共20章,看完,任何Java项目集成无压力

Activit流程引擎 本人水平,刚自学java一个多月,然后看视频做的笔记,全部傻瓜式截图教程,反正我学习之前没在网上搜索到任何小白教程, Activit官方的教程真心看不懂,因为都是文字 没具体创建步奏,所以对新手来说很无奈, 然后吧,就把自己的学习经验贡献出来啦 最小白的文档,看完之后,集成到任何java项目中都无压力,我最后的是做了个Jfinal集成,估计这是网上搜到最全的容易懂的入门学习文档,本人自学java一个月,反正我看官方例子什么的都看不懂,然后各搜素也没收到教程视频,还好有别人

Java 进行四则运算

四则运算的基础原理是将中缀表达式转换成为后缀表达式.然后进行计算. 转换思路和原理,可以参考将中缀表达式转化为后缀表达式 import java.math.BigDecimal; import java.util.ArrayList; import java.util.List; import java.util.Stack; import java.util.regex.Pattern; public class Arithmetic { //操作符stack private Stack<St

c++对象创建带括号与无括号的区别

class Test{public: Test() {} Test(int a) {}} 1.栈上创建对象 1.1 无括号 Test a; // 调用默认构造函数,栈上分配内存创建对象 1.2 有括号 Test a(); // 无任何意义,声明一个返回值为Test对象的无参函数 1.3 有括号+参数 Test a(2); // 调用构造函数Test(int a),栈上分配内存创建对象 2.堆上创建对象 2.1 无括号 Test *a = new Test; // 调用默认构造函数(若由编译器生成

Java中四则运算的那些坑

使用Java开发多年,感觉自己的水平也在不断提升,但是被Java狂虐却从来都没变过,而且任何一个Java的小角落,都能把我虐的体无完肤,但是无奈要靠Java吃饭,还得恬着脸继续使用下去.说说最近遇到的问题,则于新工作属于互联网金融,所以里面涉及到了大量的资金计算,资金计算对数字要求的比较严谨,作为一个粗心而又自大的Java程序员,一直没把这个当回事儿,于是又被Java吊打一遍.下面记录一下Java中四则运算的一些需要注意的小坑. 数学计算,免不了要想到 int long double 这种数据类

Java实现 四则运算生成 (戴国权 &amp; 关绍华)

  GitHub仓库:https://github.com/BiuBiuBangBoom/mathcreate   项目要求: 题目:实现一个自动生成小学四则运算题目的命令行程序说明: 说明: 自然数:0, 1, 2, -. 真分数:1/2, 1/3, 2/3, 1/4, 1'1/2, -. 运算符:+, ?, ×, ÷. 括号:(, ). 等号:=. 分隔符:空格(用于四则运算符和等号前后). 算术表达式: e = n | e1 + e2 | e1 ? e2 | e1 × e2 | e1 ÷

有括号 or 无括号

在编写Scala程序的时候,经常会定义或调用一些方法,经常会发现某些无参方法既可以写括号调用也可以不加括号调用,在开发者定义方法时也会面临这样的选择,看起来对我们的程序并没有什么影响,但是对于一些标准还是遵守比较好. Scala鼓励将不带参数且没有副作用的方法定义为无参数的风格,即省略空括号.但是对于有副作用的方法不要这样做,因为那样看起来像是在使用字段.例如:println(). 另一种判断的方法是:如果你调用的函数执行了操作就使用括号,但如果仅提供了对某个属性的访问,那么省略空括号.