java BigDecimal类型的计算器源码

废话不多说直接上代码

public class Test {
    public static void main(String[] args) {
        System.out.println(exec("(((-2+4)+3)*((-1-5.3)*-2)-5)*3.1415926"));
    }


    /**
     *
     * @param inputs
     *            带括号的四则表达式
     * @return 运算结果
     */
    public static BigDecimal exec(String inputs) {
        int leftIndex = inputs.lastIndexOf('('); // 16
        if (leftIndex == -1) {
            // 字符串中没有括号 直接调用calc
            return calculator(inputs);
        } else {
            // 如果有括弧先找最里面的(位置 再找对应的)位置,调用exec
            int rightIndex = inputs.substring(leftIndex).indexOf(')') + leftIndex;
            // 去独立的表达式,运算 calc(-1-5)
            BigDecimal res = calculator(inputs.substring(leftIndex + 1, rightIndex));
            // 重新组织表达式
            inputs = inputs.substring(0, leftIndex) + res
                    + inputs.substring(rightIndex + 1);
            return exec(inputs);
        }
    }

    /**
     *
     * @param exp
     *            不带括号的四则表达式
     * @return 运算结果
     */
    public static BigDecimal calculator(String exp) {
        // 1 . 获取所有四则运算的数字
        List<BigDecimal> numbers = sliptNumbers(exp);
        // 2. 获取所有四则运算的操作符号
        List<Character> ops = sliptOperator(exp);
        // 3. 先乘车运算
        // 遍历运算符中的*和/
        for (int i = 0; i < ops.size(); i++) {
            // * /
            // 获取运算符(不移除)
            char op = ops.get(i);

            // 如果是 * 或者 /, 从运算符的容器中移除,同是从数字容器中到对应该运算符位置的两个数字(移除数据,后面所有数据往前顺序移动)
            if (op == '*' || op == '/') {
                // 从运算符的容器中移除
                ops.remove(i);// 移除当前位置

                // 从数字容器中获取对应该运算符位置的两个数字(移除)
                BigDecimal d1 = numbers.remove(i);
                BigDecimal d2 = numbers.remove(i);

                // 运算
                d1 = op == '*' ? d1.multiply(d2)  : d1.divide(d2,9, BigDecimal.ROUND_HALF_UP) ;

                // 把运算结果插入到数字容器中的i位置
                numbers.add(i, d1);// 插入到i的位置 原来从i位置一直到最后的数据,都要往后瞬移一位
                // numbers.set(i, d1);//设置i位置上的数据为d1,其余不变
                i--;// 移除后,后面所有运算符往前移动,为了保证下一个运算符不被遗漏,所以i--
            }// end if (op == '*' || op == '/') {

        }// end for (int i = 0 ; i < ops.size(); i++) {

        // 4. 再加减运算
        while (!ops.isEmpty()) {
            // 每次去运算容器中第一个运算符
            char op = ops.remove(0);
            // 每次从数字容器中两次取第一个数字
            BigDecimal d1 = numbers.remove(0);
            BigDecimal d2 = numbers.remove(0);

            // 计算
            d1 = op == '+' ? d1.add(d1.add(d2))  : d1.add(d1.subtract(d2));

            // 把结果插入到数字容器中的第一个位置
            numbers.add(0, d1);
        }

        // 5. 返回结果

        return numbers.get(0);
    }

    /**
     * 从表达式中分离所有的运算符
     *
     * @param exp
     */
    private static List<Character> sliptOperator(String exp) {
        List<Character> ops = new ArrayList<Character>();
        // -8*-2+3/-1-5*-2-5
        // 把真实表达式变成下面的表达式
        String formaterExp = formaterExp(exp);
        // @8*@2+3/@1-5*@2-5

        StringTokenizer st = new StringTokenizer(formaterExp, "@0123456789.");
        while (st.hasMoreTokens()) {
            String opStr = st.nextElement() + "";// 取出分割符号之间的数据
            // System.out.println(numStr);
            // 如果前面是@ 变为负数
            ops.add(opStr.charAt(0));
        }
        return ops;
    }

    /**
     * 从表达式中分离所有的数字
     *
     * @param exp
     *            -8*-2+3/-1-5*-2-5 表达式
     */
    private static List< BigDecimal> sliptNumbers(String exp) {
        List<BigDecimal> numbers = new ArrayList<BigDecimal>();
        // -8*-2+3/-1-5*-2-5
        // 把真实表达式变成下面的表达式
        String formaterExp = formaterExp(exp);
        // @8*@2+3/@1-5*@2-5

        StringTokenizer st = new StringTokenizer(formaterExp, "+-*/");
        while (st.hasMoreTokens()) {
            String numStr = st.nextElement() + "";// 取出分割符号之间的数据
            // System.out.println(numStr);
            // 如果前面是@ 变为负数
            if (numStr.charAt(0) == '@') {
                numStr = "-" + numStr.substring(1);
            }

            // 把数字型的字符串变成数字
            numbers.add(new BigDecimal(numStr));
        }
        return numbers;
    }

    private static String formaterExp(String exp) {
        int index = 0;
        while (index < exp.length()) {
            char c = exp.charAt(index);
            // 判断是否是-符号
            // -代表的是负数 第一个,前一字符*/
            if (c == '-') {
                // 第一个,
                if (index == 0) {
                    exp = "@" + exp.substring(1);
                } else {
                    // 前一字符* /
                    if (exp.charAt(index - 1) == '*'
                            || exp.charAt(index - 1) == '/') {
                        exp = exp.substring(0, index) + "@"
                                + exp.substring(index + 1);
                    }
                }
            }

            index++;
            
        }
        return exp;
    }
}

在遇到除法的时候是通过这行代码限制保留的小数位。

d1 = op == '*' ? d1.add(d1.multiply(d2))  : d1.add(d1.divide(d2,9, BigDecimal.ROUND_HALF_UP)) ;

 内容参考了https://github.com/tedhappy/Java-calculator/blob/master/CalcDemo.java

但是他的是double类型的我改为了BigDecimal类型尽量去避免了精度丢失的问题

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值