Untitled

mail@pastecode.io avatar
unknown
plain_text
5 months ago
8.6 kB
3
Indexable
import java.util.*;

public class Calculator {

    // Bản đồ lưu trữ độ ưu tiên của các toán tử và hàm
    private static final Map<String, Integer> precedence = new HashMap<>();
    // Bản đồ lưu trữ các hằng số như pi và e
    private static final Map<String, Double> constants = new HashMap<>();

    // Khởi tạo các bản đồ với các giá trị cụ thể
    static {
        // Thiết lập độ ưu tiên cho các toán tử và hàm
        precedence.put("+", 1);
        precedence.put("-", 1);
        precedence.put("x", 2);  // Phép nhân
        precedence.put("/", 2);  // Phép chia
        precedence.put("%", 2);  // Phép chia lấy dư
        precedence.put("sin", 3); // Hàm sin
        precedence.put("cos", 3); // Hàm cos
        precedence.put("tan", 3); // Hàm tan
        precedence.put("ln", 3);  // Hàm ln (logarit tự nhiên)
        precedence.put("lg", 3);  // Hàm lg (logarit cơ số 10)
        precedence.put("(", 0);   // Độ ưu tiên của dấu ngoặc mở

        // Thiết lập các hằng số
        constants.put("pi", Math.PI);
        constants.put("e", Math.E);
    }

    // Hàm chính để tính toán biểu thức
    public static double evaluateExpression(String expression) {
        // Bước 1: Tokenize - Tách biểu thức thành các token
        List<String> tokens = tokenize(expression);
        // Bước 2: Chuyển đổi biểu thức từ dạng trung tố sang hậu tố
        Queue<String> postfix = toPostfix(tokens);
        // Bước 3: Tính toán giá trị biểu thức hậu tố
        return evaluatePostfix(postfix);
    }

    // Hàm tokenize - Tách biểu thức thành các token
    private static List<String> tokenize(String expression) {
        List<String> tokens = new ArrayList<>();
        StringBuilder number = new StringBuilder();   // Để lưu các số hoặc số thập phân
        StringBuilder function = new StringBuilder(); // Để lưu tên các hàm toán học

        for (int i = 0; i < expression.length(); i++) {
            char c = expression.charAt(i);

            if (Character.isDigit(c) || c == '.') {  // Nếu ký tự là số hoặc dấu '.'
                number.append(c); // Thêm vào number
            } else {
                if (number.length() > 0) {  // Nếu đã có số được lưu
                    tokens.add(number.toString()); // Thêm số vào danh sách tokens
                    number.setLength(0); // Xóa bộ nhớ tạm number
                }
                if (Character.isLetter(c)) { // Nếu ký tự là chữ cái
                    function.append(c); // Thêm vào function
                } else {
                    if (function.length() > 0) { // Nếu đã có hàm được lưu
                        tokens.add(function.toString()); // Thêm hàm vào danh sách tokens
                        function.setLength(0); // Xóa bộ nhớ tạm function
                    }
                    if (c != ' ') { // Bỏ qua khoảng trắng
                        tokens.add(String.valueOf(c)); // Thêm ký tự vào danh sách tokens
                    }
                }
            }
        }

        // Xử lý các số hoặc hàm còn sót lại
        if (number.length() > 0) {
            tokens.add(number.toString());
        }
        if (function.length() > 0) {
            tokens.add(function.toString());
        }

        return tokens;
    }

    // Hàm chuyển đổi từ trung tố (infix) sang hậu tố (postfix) sử dụng thuật toán Shunting-yard
    private static Queue<String> toPostfix(List<String> tokens) {
        Queue<String> output = new LinkedList<>();
        Stack<String> operators = new Stack<>();

        for (String token : tokens) {
            if (isNumber(token) || isConstant(token)) {
                output.add(token); // Nếu token là số hoặc hằng số, thêm vào output
            } else if (isFunction(token)) {
                operators.push(token); // Nếu token là hàm, đẩy vào stack
            } else if (token.equals("(")) {
                operators.push(token); // Nếu token là dấu ngoặc mở, đẩy vào stack
            } else if (token.equals(")")) {
                while (!operators.isEmpty() && !operators.peek().equals("(")) {
                    output.add(operators.pop()); // Đẩy các toán tử trong stack vào output cho đến khi gặp dấu ngoặc mở
                }
                operators.pop(); // Bỏ dấu ngoặc mở khỏi stack
                if (!operators.isEmpty() && isFunction(operators.peek())) {
                    output.add(operators.pop()); // Đẩy hàm vào output nếu có
                }
            } else {
                // Xử lý các toán tử
                while (!operators.isEmpty() && precedence.get(token) <= precedence.get(operators.peek())) {
                    output.add(operators.pop()); // Đẩy toán tử từ stack vào output dựa trên độ ưu tiên
                }
                operators.push(token); // Đẩy toán tử hiện tại vào stack
            }
        }

        while (!operators.isEmpty()) {
            output.add(operators.pop()); // Đẩy tất cả toán tử còn lại trong stack vào output
        }

        return output;
    }

    // Hàm tính toán biểu thức hậu tố
    private static double evaluatePostfix(Queue<String> postfix) {
        Stack<Double> stack = new Stack<>();

        while (!postfix.isEmpty()) {
            String token = postfix.poll();
            if (isNumber(token)) {
                stack.push(Double.parseDouble(token)); // Nếu token là số, đẩy vào stack
            } else if (isConstant(token)) {
                stack.push(constants.get(token)); // Nếu token là hằng số, đẩy giá trị hằng số vào stack
            } else if (isFunction(token)) {
                double a = stack.pop();
                stack.push(evaluateFunction(token, a)); // Tính toán hàm với tham số từ stack và đẩy kết quả vào stack
            } else {
                double b = stack.pop();
                double a = stack.pop();
                stack.push(evaluateOperator(token, a, b)); // Tính toán phép toán với hai tham số từ stack và đẩy kết quả vào stack
            }
        }

        return stack.pop(); // Giá trị cuối cùng trong stack là kết quả của biểu thức
    }

    // Hàm thực hiện các hàm toán học như sin, cos, tan, ln, lg
    private static double evaluateFunction(String function, double a) {
        switch (function) {
            case "sin": return Math.sin(a);
            case "cos": return Math.cos(a);
            case "tan": return Math.tan(a);
            case "ln": return Math.log(a);
            case "lg": return Math.log10(a);
            default: throw new IllegalArgumentException("Unknown function: " + function);
        }
    }

    // Hàm thực hiện các phép toán cơ bản như +, -, x, /, %
    private static double evaluateOperator(String operator, double a, double b) {
        switch (operator) {
            case "+": return a + b;
            case "-": return a - b;
            case "x": return a * b;
            case "/": return a / b;
            case "%": return a % b;
            default: throw new IllegalArgumentException("Unknown operator: " + operator);
        }
    }

    // Kiểm tra xem token có phải là một số không
    private static boolean isNumber(String token) {
        try {
            Double.parseDouble(token);
            return true;
        } catch (NumberFormatException e) {
            return false;
        }
    }

    // Kiểm tra xem token có phải là một hằng số không
    private static boolean isConstant(String token) {
        return constants.containsKey(token);
    }

    // Kiểm tra xem token có phải là một hàm toán học không
    private static boolean isFunction(String token) {
        return precedence.containsKey(token) && precedence.get(token) == 3;
    }

    public static void main(String[] args) {
        // Test với một biểu thức mẫu
        String expression = "3 + 5 x ( 2 - 8 ) / 2 + sin(pi / 2)";
        System.out.println("Result: " + evaluateExpression(expression)); // Kết quả là 0.0
    }
}
Leave a Comment