Untitled

mail@pastecode.io avatar
unknown
plain_text
5 months ago
6.3 kB
3
Indexable
package com.example.calculator;
import java.util.*;

public class Calculator {

    private static final Map<String, Integer> precedence = new HashMap<>();
    private static final Map<String, Double> constants = new HashMap<>();
    static {
        precedence.put("+", 1);
        precedence.put("-", 1);
        precedence.put("*", 2);
        precedence.put("/", 2);
        precedence.put("%", 2);
        precedence.put("^", 3);
        precedence.put("(", 0);
        precedence.put(")", 0);

        constants.put("\u03C0", Math.PI);
        constants.put("e", Math.E);
    }

    public static double evaluateExpression(String expression) {
        List<String> tokens = tokenize(expression.trim());
        Queue<String> postfix = toPostfix(tokens);
        return evaluatePostfix(postfix);
    }

    private static List<String> tokenize(String expression) {
        List<String> tokens = new ArrayList<>();
        StringBuilder number = new StringBuilder();
        StringBuilder function = new StringBuilder();
        boolean expectNegativeNumber = true;

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

                char c = expression.charAt(i);

                if (Character.isDigit(c) || c == '.') {
                    number.append(c);
                    expectNegativeNumber = false;
                } else {
                    if (number.length() > 0) {
                        tokens.add(number.toString());
                        number.setLength(0);
                    }
                    if (Character.isLetter(c)) {
                        function.append(c);
                        expectNegativeNumber = false;
                    } else {
                        if (function.length() > 0) {
                            tokens.add(function.toString());
                            function.setLength(0);
                        }
                        if(c == '-' && expectNegativeNumber) {
                            number.append(c);
                        }
                        else {
                            if (c != ' ') {
                                tokens.add(String.valueOf(c));
                            }
                            expectNegativeNumber = (c == '(' || precedence.containsKey(String.valueOf(c)));
                        }

                    }
                }
            }

            if (number.length() > 0) {
                tokens.add(number.toString());
            }
            if (function.length() > 0) {
                tokens.add(function.toString());
            }



        return tokens;
    }

    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);
            } else if (isFunction(token)) {
                operators.push(token);
            } else if (token.equals("(")) {
                operators.push(token);
            } else if (token.equals(")")) {
                while (!operators.isEmpty() && !operators.peek().equals("(")) {
                    output.add(operators.pop());
                }
                operators.pop();  // Remove '('
                if (!operators.isEmpty() && isFunction(operators.peek())) {
                    output.add(operators.pop());
                }
            } else { // Operator
                while (!operators.isEmpty() && precedence.get(token) <= precedence.get(operators.peek())) {
                    output.add(operators.pop());
                }
                operators.push(token);
            }
        }

        while (!operators.isEmpty()) {
            output.add(operators.pop());
        }

        return output;
    }

    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));
            } else if (isConstant(token)) {
                stack.push(constants.get(token));
            } else if (isFunction(token)) {
                double a = stack.pop();
                stack.push(evaluateFunction(token, a));
            } else { // Operator
                double b = stack.pop();
                double a = stack.pop();
                stack.push(evaluateOperator(token, a, b));
            }
        }

        return stack.pop();
    }

    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);
        }
    }

    private static double evaluateOperator(String operator, double a, double b) {
        switch (operator) {
            case "+": return a + b;
            case "-": return a - b;
            case "*": return a * b;
            case "/": {
                if(b == 0) throw new ArithmeticException("Not division by zero: " + b);
                else return a / b;
            }
            case "%": return a % b;
            case "^": return Math.pow(a, b);
            default: throw new IllegalArgumentException("Unknown operator: " + operator);
        }
    }

    private static boolean isNumber(String token) {
        try {
            Double.parseDouble(token);
            return true;
        } catch (NumberFormatException e) {
            return false;
        }
    }

    private static boolean isConstant(String token) {
        return constants.containsKey(token);
    }

    private static boolean isFunction(String token) {
        return token.equals("sin") || token.equals("cos") || token.equals("tan") || token.equals("ln") ||token.equals("lg");
    }
}
Leave a Comment