Calculator
HW
Queue Task: Modify the CalculatorQueue to support more complex operations, such as multiplication and division.
import java.util.LinkedList;
import java.util.Queue;
// Create a queue to store operations
Queue<String> operations = new LinkedList<>();
// Enqueue tasks
operations.add("3 + 5");
operations.add("2 - 1");
operations.add("4 * 6");
operations.add("8 / 2");
// Process tasks in order
while (!operations.isEmpty()) {
String operation = operations.poll(); // Dequeue
System.out.println("Processing: " + operation);
double result = evaluate(operation);
System.out.println("Result: " + result);
}
// Evaluates simple binary expressions like "3 + 5"
public static double evaluate(String expr) {
String[] parts = expr.split(" ");
if (parts.length != 3) {
throw new IllegalArgumentException("Invalid operation format: " + expr);
}
double left = Double.parseDouble(parts[0]);
String operator = parts[1];
double right = Double.parseDouble(parts[2]);
return switch (operator) {
case "+" -> left + right;
case "-" -> left - right;
case "*" -> left * right;
case "/" -> right != 0 ? left / right : Double.NaN;
default -> throw new IllegalArgumentException("Unknown operator: " + operator);
};
}
Processing: 3 + 5
Result: 8.0
Processing: 2 - 1
Result: 1.0
Processing: 4 * 6
Result: 24.0
Processing: 8 / 2
Result: 4.0
- Stack Task: Modify the CalculatorStack to reverse the order of addition and handle operations in the LIFO sequence.
import java.util.Stack;
// Create a stack to store operations (LIFO)
Stack<String> operations = new Stack<>();
// Push some example operations
operations.push("3 + 5");
operations.push("2 - 1");
operations.push("4 * 6");
operations.push("8 / 2");
operations.push("7 + 2"); // addition that will be reversed to 2 + 7
// Process in LIFO order
while (!operations.isEmpty()) {
String operation = operations.pop();
System.out.println("Processing (LIFO): " + operation);
double result = evaluate(operation);
System.out.println("Result: " + result);
System.out.println("-----");
}
/**
* Parse and evaluate a simple binary expression of the form "A op B".
* If op is "+", swap A and B before adding.
*/
public static double evaluate(String expr) {
String[] parts = expr.trim().split("\\s+");
if (parts.length != 3) {
throw new IllegalArgumentException("Invalid format, expected \"A op B\": " + expr);
}
double left = Double.parseDouble(parts[0]);
String op = parts[1];
double right = Double.parseDouble(parts[2]);
switch (op) {
case "+":
// reverse the order for addition
return right + left;
case "-":
return left - right;
case "*":
return left * right;
case "/":
if (right == 0) {
System.err.println("Warning: division by zero in \"" + expr + "\"");
return Double.NaN;
}
return left / right;
default:
throw new IllegalArgumentException("Unknown operator: " + op);
}
}
Processing (LIFO): 7 + 2
Result: 9.0
-----
Processing (LIFO): 8 / 2
Result: 4.0
-----
Processing (LIFO): 4 * 6
Result: 24.0
-----
Processing (LIFO): 2 - 1
Result: 1.0
-----
Processing (LIFO): 3 + 5
Result: 8.0
-----
- Add a method to both the stack and queue programs to handle invalid operations and display an error message.
// CalculatorStack.java
import java.util.Stack;
public static Double safeEvaluate(String expr) {
try {
return evaluate(expr);
} catch (IllegalArgumentException e) {
System.err.println("Error: " + e.getMessage());
return null;
}
}
public static double evaluate(String expr) {
String[] parts = expr.trim().split("\\s+");
if (parts.length != 3) {
throw new IllegalArgumentException("Invalid format, expected \"A op B\"");
}
double left;
double right;
try {
left = Double.parseDouble(parts[0]);
right = Double.parseDouble(parts[2]);
} catch (NumberFormatException nfe) {
throw new IllegalArgumentException("Operands must be numbers");
}
String op = parts[1];
switch (op) {
case "+":
// reversed addition
return right + left;
case "-":
return left - right;
case "*":
return left * right;
case "/":
if (right == 0) {
throw new IllegalArgumentException("Division by zero");
}
return left / right;
default:
throw new IllegalArgumentException("Unknown operator: " + op);
}
}
Stack<String> operations = new Stack<>();
operations.push("3 + 5");
operations.push("2 - 1");
operations.push("4 * 6");
operations.push("8 / 2");
operations.push("7 + 2");
operations.push("oops"); // invalid format
operations.push("5 $ 3"); // unknown operator
while (!operations.isEmpty()) {
String op = operations.pop();
System.out.println("Processing (LIFO): " + op);
Double result = safeEvaluate(op);
if (result != null) {
System.out.println("Result: " + result);
}
System.out.println("-----");
}
Processing (LIFO): 5 $ 3
Error: Unknown operator: $
-----
Processing (LIFO): oops
Error: Invalid format, expected "A op B"
-----
Processing (LIFO): 7 + 2
Result: 9.0
-----
Processing (LIFO): 8 / 2
Result: 4.0
-----
Processing (LIFO): 4 * 6
Result: 24.0
-----
Processing (LIFO): 2 - 1
Result: 1.0
-----
Processing (LIFO): 3 + 5
Result: 8.0
-----
- Create a method for both programs to display all operations before processing them, and track the result after each operation.
// CalculatorQueue.java
import java.util.LinkedList;
import java.util.Queue;
import java.util.List;
import java.util.ArrayList;
public class CalculatorQueue {
public static void main(String[] args) {
// Create a queue to store operations
Queue<String> operations = new LinkedList<>();
operations.add("3 + 5");
operations.add("2 - 1");
operations.add("4 * 6");
operations.add("8 / 0"); // division by zero
operations.add("bad input"); // invalid format
// Copy operations for display and result tracking
List<String> opList = new ArrayList<>(operations);
displayOperations(opList);
List<Double> results = new ArrayList<>();
System.out.println("Processing and tracking results:");
while (!operations.isEmpty()) {
String op = operations.poll();
Double result = safeEvaluate(op);
results.add(result);
}
displayResults(opList, results);
}
// Display all pending operations
public static void displayOperations(List<String> ops) {
System.out.println("Operations to process (FIFO order):");
for (String op : ops) {
System.out.println(" - " + op);
}
System.out.println("-----");
}
// Display operations with their results
public static void displayResults(List<String> ops, List<Double> results) {
System.out.println("Summary of results:");
for (int i = 0; i < ops.size(); i++) {
System.out.printf("%s = %s\n", ops.get(i),
results.get(i) == null ? "Error" : results.get(i));
}
}
public static Double safeEvaluate(String expr) {
try {
return evaluate(expr);
} catch (IllegalArgumentException e) {
System.err.println("Error: " + e.getMessage() + " in '" + expr + "'");
return null;
}
}
public static double evaluate(String expr) {
String[] parts = expr.trim().split("\\s+");
if (parts.length != 3) {
throw new IllegalArgumentException("Invalid format, expected 'A op B'");
}
double left, right;
try {
left = Double.parseDouble(parts[0]);
right = Double.parseDouble(parts[2]);
} catch (NumberFormatException nfe) {
throw new IllegalArgumentException("Operands must be numbers");
}
switch (parts[1]) {
case "+": return left + right;
case "-": return left - right;
case "*": return left * right;
case "/":
if (right == 0) throw new IllegalArgumentException("Division by zero");
return left / right;
default: throw new IllegalArgumentException("Unknown operator: " + parts[1]);
}
}
}
// CalculatorStack.java
import java.util.Stack;
import java.util.List;
import java.util.ArrayList;
public class CalculatorStack {
public static void main(String[] args) {
Stack<String> operations = new Stack<>();
operations.push("3 + 5");
operations.push("2 - 1");
operations.push("4 * 6");
operations.push("8 / 2");
operations.push("7 + 2");
operations.push("oops"); // invalid format
operations.push("5 $ 3"); // unknown operator
// Copy operations for display and result tracking
List<String> opList = new ArrayList<>(operations);
displayOperations(opList);
List<Double> results = new ArrayList<>();
System.out.println("Processing and tracking results:");
while (!operations.isEmpty()) {
String op = operations.pop();
Double result = safeEvaluate(op);
results.add(result);
}
displayResults(opList, results);
}
// Display all pending operations
public static void displayOperations(List<String> ops) {
System.out.println("Operations to process (LIFO order):");
for (String op : ops) {
System.out.println(" - " + op);
}
System.out.println("-----");
}
// Display operations with their results
public static void displayResults(List<String> ops, List<Double> results) {
System.out.println("Summary of results:");
for (int i = 0; i < ops.size(); i++) {
System.out.printf("%s = %s\n", ops.get(i),
results.get(i) == null ? "Error" : results.get(i));
}
}
public static Double safeEvaluate(String expr) {
try {
return evaluate(expr);
} catch (IllegalArgumentException e) {
System.err.println("Error: " + e.getMessage() + " in '" + expr + "'");
return null;
}
}
public static double evaluate(String expr) {
String[] parts = expr.trim().split("\\s+");
if (parts.length != 3) {
throw new IllegalArgumentException("Invalid format, expected 'A op B'");
}
double left, right;
try {
left = Double.parseDouble(parts[0]);
right = Double.parseDouble(parts[2]);
} catch (NumberFormatException nfe) {
throw new IllegalArgumentException("Operands must be numbers");
}
String op = parts[1];
switch (op) {
case "+": return right + left; // reversed addition
case "-": return left - right;
case "*": return left * right;
case "/":
if (right == 0) throw new IllegalArgumentException("Division by zero");
return left / right;
default: throw new IllegalArgumentException("Unknown operator: " + op);
}
}
}
CalculatorQueue.main(null);
System.out.println();
CalculatorStack.main(null);
Operations to process (FIFO order):
- 3 + 5
- 2 - 1
- 4 * 6
- 8 / 0
- bad input
-----
Processing and tracking results:
Error: Division by zero in '8 / 0'
Error: Invalid format, expected 'A op B' in 'bad input'
Summary of results:
3 + 5 = 8.0
2 - 1 = 1.0
4 * 6 = 24.0
8 / 0 = Error
bad input = Error
Operations to process (LIFO order):
- 3 + 5
- 2 - 1
- 4 * 6
- 8 / 2
- 7 + 2
- oops
- 5 $ 3
-----
Processing and tracking results:
Error: Unknown operator: $ in '5 $ 3'
Error: Invalid format, expected 'A op B' in 'oops'
Summary of results:
3 + 5 = Error
2 - 1 = Error
4 * 6 = 9.0
8 / 2 = 4.0
7 + 2 = 24.0
oops = 1.0
5 $ 3 = 8.0
- Advanced Task: Implement a calculator that supports parentheses using a stack to ensure proper operation precedence.
Postfix evaulation using an array (this allows numbers to be more than 0-9)
import java.util.Stack;
/**
* Calculator that evaluates infix expressions with +, -, *, /, and parentheses using two stacks.
*/
public class CalculatorWithParentheses {
public static void main(String[] args) {
String[] tests = {
"3 + 5 * (2 - 1)",
"(1 + 2) * (3 + 4)",
"10 + (2 * 3) - (4 / 2)",
"(3 + (4 - 1)) * 5",
"7 + ((3 * (2 + 1)) - 5)"
};
for (String expr : tests) {
try {
double result = evaluate(expr);
System.out.printf("%s = %s\n", expr, result);
} catch (IllegalArgumentException e) {
System.err.printf("Error evaluating '%s': %s%n", expr, e.getMessage());
}
}
}
/**
* Evaluate an arithmetic expression with parentheses.
* @param expr Infix expression, tokens separated by spaces or not.
* @return computed result
*/
public static double evaluate(String expr) {
// Remove spaces for easier processing
expr = expr.replaceAll("\\s+", "");
Stack<Double> values = new Stack<>();
Stack<Character> ops = new Stack<>();
for (int i = 0; i < expr.length(); i++) {
char c = expr.charAt(i);
if (Character.isDigit(c) || c == '.') {
// parse number (including decimals)
int j = i;
while (j < expr.length() && (Character.isDigit(expr.charAt(j)) || expr.charAt(j) == '.')) {
j++;
}
double number = Double.parseDouble(expr.substring(i, j));
values.push(number);
i = j - 1;
} else if (c == '(') {
ops.push(c);
} else if (c == ')') {
// solve until matching '('
while (!ops.isEmpty() && ops.peek() != '(') {
applyOp(values, ops);
}
if (ops.isEmpty() || ops.pop() != '(') {
throw new IllegalArgumentException("Mismatched parentheses");
}
} else if (isOperator(c)) {
// apply ops with higher or equal precedence
while (!ops.isEmpty() && precedence(ops.peek()) >= precedence(c)) {
if (ops.peek() == '(') break;
applyOp(values, ops);
}
ops.push(c);
} else {
throw new IllegalArgumentException("Invalid character: " + c);
}
}
// finish remaining operations
while (!ops.isEmpty()) {
if (ops.peek() == '(' || ops.peek() == ')') {
throw new IllegalArgumentException("Mismatched parentheses");
}
applyOp(values, ops);
}
if (values.size() != 1) {
throw new IllegalArgumentException("Invalid expression");
}
return values.pop();
}
// Returns true for supported operators
private static boolean isOperator(char c) {
return c == '+' || c == '-' || c == '*' || c == '/';
}
// Defines operator precedence
private static int precedence(char op) {
return (op == '+' || op == '-') ? 1 : (op == '*' || op == '/') ? 2 : 0;
}
// Pops top two values and applies top operator
private static void applyOp(Stack<Double> values, Stack<Character> ops) {
if (values.size() < 2) throw new IllegalArgumentException("Insufficient values");
double b = values.pop();
double a = values.pop();
char op = ops.pop();
double result;
switch (op) {
case '+': result = a + b; break;
case '-': result = a - b; break;
case '*': result = a * b; break;
case '/':
if (b == 0) throw new IllegalArgumentException("Division by zero");
result = a / b;
break;
default: throw new IllegalArgumentException("Unknown operator: " + op);
}
values.push(result);
}
}
CalculatorWithParentheses.main(null);
3 + 5 * (2 - 1) = 8.0
(1 + 2) * (3 + 4) = 21.0
10 + (2 * 3) - (4 / 2) = 14.0
(3 + (4 - 1)) * 5 = 30.0
7 + ((3 * (2 + 1)) - 5) = 11.0