botgob

calculator

Feb 16th, 2021
853
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 9.06 KB | None | 0 0
  1. import java.util.*;
  2.  
  3. import static java.lang.Double.NaN;
  4. import static java.lang.Double.valueOf;
  5. import static java.lang.Math.incrementExact;
  6. import static java.lang.Math.pow;
  7.  
  8.  
  9. /*
  10.  *   A calculator for rather simple arithmetic expressions
  11.  *
  12.  *   This is not the program, it's a class declaration (with methods) in it's
  13.  *   own file (which must be named Calculator.java)
  14.  *
  15.  *   NOTE:
  16.  *   - No negative numbers implemented
  17.  */
  18. public class Calculator {
  19.  
  20.     // Here are the only allowed instance variables!
  21.     // Error messages (more on static later)
  22.     final static String MISSING_OPERAND = "Missing or bad operand";
  23.     final static String DIV_BY_ZERO = "Division with 0";
  24.     final static String MISSING_OPERATOR = "Missing operator or parenthesis";
  25.     final static String OP_NOT_FOUND = "Operator not found";
  26.  
  27.     // Definition of operators
  28.     final static String OPERATORS = "+-*/^";
  29.  
  30.     // Method used in REPL
  31.     double eval(String expr) {
  32.         if (expr.length() == 0) {
  33.             return NaN;
  34.         }
  35.         List<String> tokens = tokenize(expr);
  36.         List<String> postfix = infix2Postfix(tokens);
  37.         return evalPostfix(postfix);
  38.     }
  39.  
  40.     // ------  Evaluate RPN expression -------------------
  41.  
  42.     double evalPostfix(List<String> postfix) {
  43.         Deque<String> stack = new ArrayDeque<String>();
  44.         List<String> results = new ArrayList<String>();
  45.         double a,b;
  46.         // If there's just one value, it gets returned.
  47.         if (postfix.size() == 1){
  48.             return valueOf(postfix.get(0));
  49.         }
  50.         for (int i = 0; i < postfix.size() ; i++) {
  51.             // If the current index isn't an operator,
  52.             // it gets added to the queue.
  53.             if(!isOperator(postfix.get(i))){
  54.                 stack.push(postfix.get(i));
  55.             }
  56.             // If it is an operator, then it calculates
  57.             // all the numbers before in the queue using the
  58.             // current operator.
  59.             else{
  60.                 a = Double.valueOf(stack.pop());
  61.                 b = Double.valueOf(stack.pop());
  62.                 stack.push(applyOperator(postfix.get(i), a, b)+"");
  63.             }
  64.         }
  65.         return Double.valueOf(stack.pop());
  66.     }
  67.  
  68.     // Checks if the current String contains an operator.
  69.     boolean isOperator(String s){
  70.         String[] operators = {"+","-", "*", "/", "^", "(", ")"};
  71.         for (String operator : operators) {
  72.             if (operator.contains(s)) {
  73.                 return true;
  74.             }
  75.         }
  76.         return false;
  77.     }
  78.  
  79.     double applyOperator(String op, double d1, double d2) {
  80.         switch (op) {
  81.             case "+":
  82.                 return d1 + d2;
  83.             case "-":
  84.                 return d2 - d1;
  85.             case "*":
  86.                 return d1 * d2;
  87.             case "/":
  88.                 if (d1 == 0) {
  89.                     throw new IllegalArgumentException(DIV_BY_ZERO);
  90.                 }
  91.                 return d2 / d1;
  92.             case "^":
  93.                 return pow(d2, d1);
  94.         }
  95.         throw new RuntimeException(OP_NOT_FOUND);
  96.     }
  97.  
  98.     // ------- Infix 2 Postfix ------------------------
  99.  
  100.     List<String> infix2Postfix(List<String> infix) {
  101.         List<String> postFix = new ArrayList<String>();
  102.         Deque<String> que = new ArrayDeque<String>();
  103.         boolean latestBracket = false;
  104.         for (String s : infix) {
  105.  
  106.             // Checks if the current index is an operator
  107.             // , if it isnt an operator, it adds it to
  108.             // postFix.
  109.             if (isOperator(s)) {
  110.  
  111.                 // Checks if the latest operator added to queue is
  112.                 // an opening bracket
  113.                 if (!que.isEmpty() && !que.peek().contains("(")) {
  114.                     latestBracket = false;
  115.                 } else if (!que.isEmpty()) {
  116.                     latestBracket = true;
  117.                 }
  118.  
  119.                 // Code for brackets.
  120.                 // If the latest operator was an opening bracket and
  121.                 // the current operator isnt a bracket, it will be
  122.                 // added to the queue.
  123.                 if (latestBracket && !s.contains("(") && !s.contains(")")) {
  124.                     que.push(s);
  125.                     latestBracket = false;
  126.                 }
  127.                 // If the current operator is a open bracket
  128.                 // it will be added to the queue.
  129.                 else if (s.contains("(")) {
  130.                     que.push(s);
  131.                     latestBracket = true;
  132.                 }
  133.                 // If the current operator is a closing bracket
  134.                 // all operators will be popped until a closing
  135.                 // bracket is the next in que. It will be popped
  136.                 // but not put anywhere. The for loop the breaks.
  137.                 else if (s.contains(")")) {
  138.                     int stackSize = que.size();
  139.                     for (int k = 0; k < stackSize; k++) {
  140.                         if (!que.peek().contains("(")) {
  141.                             postFix.add(que.pop());
  142.                         } else {
  143.                             que.pop();
  144.                             break;
  145.                         }
  146.                     }
  147.                 }
  148.                 // Code for non-bracket operators.
  149.                 else {
  150.                     // If the queue is empty the new operator will simply be
  151.                     // put in the queue.
  152.                     if (que.isEmpty()) {
  153.                         que.push(s);
  154.                     }
  155.                     // If the top of the queue has higher precedence than the
  156.                     // current operator to be added, then it will be popped
  157.                     // and the new operator will be added. However if there are
  158.                     // more than one operator with higher precedence
  159.                     // all of those will be popped as well.
  160.                     else if (getPrecedence(que.peek()) > getPrecedence(s)) {
  161.                         postFix.add(que.pop());
  162.                         while (true) {
  163.                             if (!que.isEmpty() && getPrecedence(que.peek()) > getPrecedence(s)) {
  164.                                 postFix.add(que.pop());
  165.                             } else break;
  166.                         }
  167.                         que.push(s);
  168.                     }
  169.                     // If both the top of the queue and the operator to be added has the
  170.                     // same precedence, then the code checks the associativity. If the
  171.                     // new operator has left association then the old operator will
  172.                     // be popped. In both cases the new one gets pushed in to the queue.
  173.                     else if (getPrecedence(que.peek()) == getPrecedence(s)) {
  174.                         if (getAssociativity(s) == Assoc.LEFT) {
  175.                             postFix.add(que.pop());
  176.                         }
  177.                         que.push(s);
  178.                     }
  179.                     // If the new operator has higher precedence then it gets pushed to
  180.                     // the top of the queue.
  181.                     else if (getPrecedence(que.peek()) < getPrecedence(s)) {
  182.                         que.push(s);
  183.                     }
  184.  
  185.                 }
  186.             } else postFix.add(s);
  187.         }
  188.         // If there are any operators left in queue they will be added
  189.         // to the end of the postFix list.
  190.         while(!que.isEmpty()){
  191.             postFix.add(que.pop());
  192.         }
  193.         System.out.println(postFix.toString());
  194.         return postFix;
  195.     }
  196.  
  197.     int getPrecedence(String op) {
  198.         if ("+-".contains(op)) {
  199.             return 2;
  200.         } else if ("*/".contains(op)) {
  201.             return 3;
  202.         } else if ("^".contains(op)) {
  203.             return 4;
  204.         } else {
  205.             throw new RuntimeException(OP_NOT_FOUND);
  206.         }
  207.     }
  208.  
  209.     Assoc getAssociativity(String op) {
  210.         if ("+-*/".contains(op)) {
  211.             return Assoc.LEFT;
  212.         } else if ("^".contains(op)) {
  213.             return Assoc.RIGHT;
  214.         } else {
  215.             throw new RuntimeException(OP_NOT_FOUND);
  216.         }
  217.     }
  218.  
  219.     enum Assoc {
  220.         LEFT,
  221.         RIGHT
  222.     }
  223.  
  224.     // ---------- Tokenize -----------------------
  225.  
  226.     // List String (not char) because numbers (with many chars)
  227.     // Using a StringTokenizer on the String we can split
  228.     // up the String and still keep the delimiters. Using simple
  229.     // regex we tell it where to split. We then add it to the list
  230.     // that then gets returned.
  231.     List<String> tokenize(String expr) {
  232.        // TODO
  233.         List<String> tokens = new ArrayList<String>();
  234.         StringTokenizer test = new StringTokenizer(expr,"[\\+\\-*/\\^ ()]+", true );
  235.         while(test.hasMoreTokens()){
  236.             tokens.add(test.nextToken());
  237.         }
  238.         // If the list has any empty indexes, they get removed.
  239.         for (int i = 0; i < tokens.size(); i++) {
  240.             if (tokens.get(i).contains(" ")){
  241.                 tokens.remove(i);
  242.                 i = 0;
  243.             }
  244.         }
  245.         return tokens;
  246.     }
  247. }
  248.  
Advertisement
Add Comment
Please, Sign In to add comment