JAVA 算数表达式的计算

2 篇文章 0 订阅

产品提出的需求:根据mtmCode表达式计算该操作步骤的工时,mtmCode为operationCode的组合(该组合为算数表达式),根据该表达式计算该操作的工时:  此处举一个建单的例子

 

此处直接上代码:

 

package com.nio.portal.common.util;

/**
 * @Title: ArithHelper
 * @Description: TODO
 * @author lulu.wang.o
 * @version V1.0
 * @date 2019-11-19
 */
public class ArithHelper {

        // 默认除法运算精度
        private static final int DEF_DIV_SCALE = 16;
        // 这个类不能实例化
        private ArithHelper() {
        }
        /**
         * 提供精确的加法运算。
         *
         * @param v1 被加数
         * @param v2 加数
         * @return 两个参数的和
         */
        public static double add(double v1, double v2) {
            java.math.BigDecimal b1 = new java.math.BigDecimal(Double.toString(v1));
            java.math.BigDecimal b2 = new java.math.BigDecimal(Double.toString(v2));
            return b1.add(b2).doubleValue();
        }
        public static double add(String v1, String v2) {
            java.math.BigDecimal b1 = new java.math.BigDecimal(v1);
            java.math.BigDecimal b2 = new java.math.BigDecimal(v2);
            return b1.add(b2).doubleValue();
        }
        /**
         * 提供精确的减法运算。
         *
         * @param v1 被减数
         * @param v2 减数
         * @return 两个参数的差
         */
        public static double sub(double v1, double v2) {
            java.math.BigDecimal b1 = new java.math.BigDecimal(Double.toString(v1));
            java.math.BigDecimal b2 = new java.math.BigDecimal(Double.toString(v2));
            return b1.subtract(b2).doubleValue();
        }
        public static double sub(String v1, String v2) {
            java.math.BigDecimal b1 = new java.math.BigDecimal(v1);
            java.math.BigDecimal b2 = new java.math.BigDecimal(v2);
            return b1.subtract(b2).doubleValue();
        }
        /**
         * 提供精确的乘法运算。
         *
         * @param v1
         *      被乘数
         * @param v2
         *      乘数
         * @return 两个参数的积
         */
        public static double mul(double v1, double v2) {
            java.math.BigDecimal b1 = new java.math.BigDecimal(Double.toString(v1));
            java.math.BigDecimal b2 = new java.math.BigDecimal(Double.toString(v2));
            return b1.multiply(b2).doubleValue();
        }
        public static double mul(String v1, String v2) {
            java.math.BigDecimal b1 = new java.math.BigDecimal(v1);
            java.math.BigDecimal b2 = new java.math.BigDecimal(v2);
            return b1.multiply(b2).doubleValue();
        }
        /**
         * 提供(相对)精确的除法运算,当发生除不尽的情况时,精确到 小数点以后10位,以后的数字四舍五入。
         *
         * @param v1
         *      被除数
         * @param v2
         *      除数
         * @return 两个参数的商
         */
        public static double div(double v1, double v2) {
            return div(v1, v2, DEF_DIV_SCALE);
        }
        public static double div(String v1, String v2) {
            java.math.BigDecimal b1 = new java.math.BigDecimal(v1);
            java.math.BigDecimal b2 = new java.math.BigDecimal(v2);
            return b1.divide(b2, DEF_DIV_SCALE, java.math.BigDecimal.ROUND_HALF_UP).doubleValue();
        }
        /**
         * 提供(相对)精确的除法运算。当发生除不尽的情况时,由scale参数指 定精度,以后的数字四舍五入。
         *
         * @param v1 被除数
         * @param v2 除数
         * @param scale 表示表示需要精确到小数点以后几位。
         * @return 两个参数的商
         */
        public static double div(double v1, double v2, int scale) {
            if (scale < 0) {
                throw new IllegalArgumentException("The  scale  must  be  a  positive  integer  or  zero");
            }
            java.math.BigDecimal b1 = new java.math.BigDecimal(Double.toString(v1));
            java.math.BigDecimal b2 = new java.math.BigDecimal(Double.toString(v2));
            return b1.divide(b2, scale, java.math.BigDecimal.ROUND_HALF_UP).doubleValue();
        }
        /**
         * 提供精确的小数位四舍五入处理。
         *
         * @param v 需要四舍五入的数字
         * @param scale 小数点后保留几位
         * @return 四舍五入后的结果
         */
        public static double round(double v, int scale) {
            if (scale < 0) {
                throw new IllegalArgumentException("The  scale  must  be  a  positive  integer  or  zero");
            }
            java.math.BigDecimal b = new java.math.BigDecimal(Double.toString(v));
            java.math.BigDecimal one = new java.math.BigDecimal("1");
            return b.divide(one, scale, java.math.BigDecimal.ROUND_HALF_UP).doubleValue();
        }
        public static double round(String v, int scale) {
            if (scale < 0) {
                throw new IllegalArgumentException("The  scale  must  be  a  positive  integer  or  zero");
            }
            java.math.BigDecimal b = new java.math.BigDecimal(v);
            java.math.BigDecimal one = new java.math.BigDecimal("1");
            return b.divide(one, scale, java.math.BigDecimal.ROUND_HALF_UP).doubleValue();
        }


        public static void main(String[] args) {
            String expression = "(3+5)*6-3";
            double result = TaskTimeCalculator.conversion(expression);
            System.out.println(expression + " = " + result);
            System.out.println();
        }
    }

 

 

package com.nio.portal.common.util;

import java.util.Collections;
import java.util.Stack;

/**
 * @Title: TaskTimeCalculator
 * @Description: 算数表达式求值,直接调用Calculator的类方法conversion(),传入算数表达式,将返回一个浮点值结果,如果计算过程错误,将返回一个NaN
 * @author lulu.wang.o
 * @version V1.0
 * @date 2019-11-19
 */

public class TaskTimeCalculator {

    private Stack<String> postfixStack = new Stack<String>();
    // 后缀式栈
    private Stack<Character> opStack = new Stack<Character>();
    // 运算符栈
    private int[] operatPriority = new int[]{0, 3, 2, 1, -1, 1, 0, 2};

    // 运用运算符ASCII码-40做索引的运算符优先级
    public static double conversion(String expression) {
        double result = 0;
        TaskTimeCalculator cal = new TaskTimeCalculator();
        try {
            expression = transform(expression);
            result = cal.calculate(expression);
        } catch (Exception e) {
            // e.printStackTrace();
            // 运算错误返回NaN
            return 0.0 / 0.0;
        }
        // return new String().valueOf(result);
        return result;
    }

    /**
     *  * 将表达式中负数的符号更改
     *  *
     *  * @param expression
     *  *  例如-2+-1*(-3E-2)-(-1) 被转为 ~2+~1*(~3E~2)-(~1)
     *  * @return
     *  
     */
    private static String transform(String expression) {
        char[] arr = expression.toCharArray();
        for (int i = 0; i < arr.length; i++) {
            if (arr[i] == '-') {
                if (i == 0) {
                    arr[i] = '~';
                } else {
                    char c = arr[i - 1];
                    if (c == '+' || c == '-' || c == '*' || c == '/' || c == '(' || c == 'E' || c == 'e') {
                        arr[i] = '~';
                    }
                }
            }
        }

        if (arr[0] == '~' || arr[1] == '(') {
            arr[0] = '-';
            return "0" + new String(arr);
        } else {
            return new String(arr);
        }
    }

    /**
     *  * 按照给定的表达式计算
     *  *
     *  * @param expression
     *  *  要计算的表达式例如:5+12*(3+5)/7
     *  * @return
     *  
     */
    public double calculate(String expression) {
        Stack<String> resultStack = new Stack<String>();
        prepare(expression);
        Collections.reverse(postfixStack);
        // 将后缀式栈反转
        String firstValue, secondValue, currentValue;
        // 参与计算的第一个值,第二个值和算术运算符
        while (!postfixStack.isEmpty()) {
            currentValue = postfixStack.pop();
            //不是运算符
            if (!isOperator(currentValue.charAt(0))) {
                // 如果不是运算符则存入操作数栈中
                currentValue = currentValue.replace("~", "-");
                resultStack.push(currentValue);
            } else {
                // 如果是运算符则从操作数栈中取两个值和该数值一起参与运算
                secondValue = resultStack.pop();
                firstValue = resultStack.pop();
                // 将负数标记符改为负号
                firstValue = firstValue.replace("~", "-");
                secondValue = secondValue.replace("~", "-");
                String tempResult = calculate(firstValue, secondValue, currentValue.charAt(0));
                resultStack.push(tempResult);
            }
        }
        return Double.valueOf(resultStack.pop());
    }

    /**
     *  * 数据准备阶段将表达式转换成为后缀式栈
     *  *
     *  * @param expression
     *  
     */
    private void prepare(String expression) {
        opStack.push(',');
        // 运算符放入栈底元素逗号,此符号优先级最低
        char[] arr = expression.toCharArray();
        int currentIndex = 0;
        // 当前字符的位置
        int count = 0;
        // 上次算术运算符到本次算术运算符的字符的长度或者之间的数值
        char currentOp, peekOp;
        // 当前操作符和栈顶操作符
        for (int i = 0; i < arr.length; i++) {
            currentOp = arr[i];
            if (isOperator(currentOp)) {
                // 如果当前字符是运算符
                if (count > 0) {
                    postfixStack.push(new String(arr, currentIndex, count));
                    // 取两个运算符之间的数字
                }
                //返回栈顶元素
                peekOp = opStack.peek();
                if (currentOp == ')') {
                    // 遇到反括号则将运算符栈中的元素移除到后缀式栈中直到遇到左括号
                    while (opStack.peek() != '(') {
                        postfixStack.push(String.valueOf(opStack.pop()));
                    }
                    opStack.pop();
                } else {
                    while (currentOp != '(' && peekOp != ',' && compare(currentOp, peekOp)) {
                        postfixStack.push(String.valueOf(opStack.pop()));
                        peekOp = opStack.peek();
                    }
                    opStack.push(currentOp);
                }
                count = 0;
                currentIndex = i + 1;
            } else {
                count++;
            }
        }
        if (count > 1 || (count == 1 && !isOperator(arr[currentIndex]))) {
            // 最后一个字符不是括号或者其他运算符的则加入后缀式栈中
            postfixStack.push(new String(arr, currentIndex, count));
        }
        while (opStack.peek() != ',') {
            postfixStack.push(String.valueOf(opStack.pop()));
            // 将操作符栈中的剩余的元素添加到后缀式栈中
        }
    }

    /**
     *  * 判断是否为算术符号
     *  *
     *  * @param c
     *  * @return
     *  
     */
    private Boolean isOperator(char c) {
        return c == '+' || c == '-' || c == '*' || c == '/' || c == '(' || c == ')';
    }

    /**
     *  * 利用ASCII码-40做下标去算术符号优先级
     *  *
     *  * @param cur
     *  * @param peek
     *  * @return
     *  
     */
    public Boolean compare(char cur, char peek) {
// 如果是peek优先级高于cur,返回true,默认都是peek优先级要低
        Boolean result = false;
        if (operatPriority[(peek) - 40] >= operatPriority[(cur) - 40]) {
            result = true;
        }
        return result;
    }

    /**
     *  * 按照给定的算术运算符做计算
     *  *
     *  * @param firstValue
     *  * @param secondValue
     *  * @param currentOp
     *  * @return
     *  
     */
    private String calculate(String firstValue, String secondValue, char currentOp) {
        String result = "";
        switch (currentOp) {
            case '+':
                result = String.valueOf(ArithHelper.add(firstValue, secondValue));
                break;
            case '-':
                result = String.valueOf(ArithHelper.sub(firstValue, secondValue));
                break;
            case '*':
                result = String.valueOf(ArithHelper.mul(firstValue, secondValue));
                break;
            case '/':
                result = String.valueOf(ArithHelper.div(firstValue, secondValue));
                break;
        }
        return result;
    }
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java中可以通过栈来实现算数表达式的求值。 具体步骤如下: 1. 创建两个栈,一个用来存储数字,一个用来存储操作符。 2. 将算数表达式转换为后缀表达式。 3. 遍历后缀表达式,如果是数字,则将其入数字栈,如果是操作符,则从数字栈中弹出两个数字进行计算,并将结果压入数字栈。 4. 最终数字栈中的唯一元素即为表达式的值。 下面是一个简单的示例代码: ``` import java.util.Stack; public class ArithmeticExpressionEvaluation { public static int evaluate(String expression) { Stack<Integer> numbers = new Stack<>(); Stack<Character> operators = new Stack<>(); for (int i = 0; i < expression.length(); i++) { char c = expression.charAt(i); if (Character.isDigit(c)) { int num = 0; while (Character.isDigit(c)) { num = num * 10 + (c - '0'); i++; c = expression.charAt(i); } i--; numbers.push(num); } else if (c == '(') { operators.push(c); } else if (c == ')') { while (operators.peek() != '(') { int num2 = numbers.pop(); int num1 = numbers.pop(); char op = operators.pop(); int result = calculate(num1, num2, op); numbers.push(result); } operators.pop(); } else if (isOperator(c)) { while (!operators.isEmpty() && precedence(operators.peek()) >= precedence(c)) { int num2 = numbers.pop(); int num1 = numbers.pop(); char op = operators.pop(); int result = calculate(num1, num2, op); numbers.push(result); } operators.push(c); } } while (!operators.isEmpty()) { int num2 = numbers.pop(); int num1 = numbers.pop(); char op = operators.pop(); int result = calculate(num1, num2, op); numbers.push(result); } return numbers.pop(); } private static int calculate(int num1, int num2, char op) { switch (op) { case '+': return num1 + num2; case '-': return num1 - num2; case '*': return num1 * num2; case '/': return num1 / num2; default: return 0; } } private static boolean isOperator(char c) { return c == '+' || c == '-' || c == '*' || c == '/'; } private static int precedence(char op) { if (op == '*' || op == '/') { return 2; } else if (op == '+' || op == '-') { return 1; } else { return 0; } } public static void main(String[] args) { String expression = "5 + ((1 + 2) * 4) - 3"; int result = evaluate(expression); System.out.println(result); // Output: 14 } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值