Creating a "calculator" to evaluate arithmetic expressions in Java - code troubles - java

I'm trying to solidify my understanding of stacks and operators by creating a simple calculator to process arithmetic expressions that involve parentheses. I feel like I have code that should work, but it's most certainly not giving me the right output.
Even though I have a method to evaluate each expression, when I try to return the number stack it does not print out any evaluated method but only all numbers inputted by the user. I want to deal with issues in input like mismatched operators or missing parentheses as well.
I attempt to run the code with simple expressions like 9 * 5 or something like (7 * 6) + (9 - 4) and it just returns the last double regardless.
Here's my code so far:
Main method
import java.util.Stack;
import javax.swing.JOptionPane;
public class Calculator {
// instance variables
private Stack < Double > nums;
private Stack < String > ops;
String list;
// constructor
public Calculator()
{
nums = new Stack < Double > ();
ops = new Stack < String > ();
}
// methods
public static boolean isDouble(String str) {
try {
Double.parseDouble(str);
} catch (NumberFormatException e) {
return false;
} catch (NullPointerException e) {
return false;
}
return true;
}
public static boolean isValidOp(String str) {
return (str == "(" || str == ")" || str == "^" || str == "*" || str == "/" || str == "+" || str == "-");
}
public int prec(String str) {
if (str == "(" || str == ")")
return 4;
if (str == "^")
return 3;
if (str == "*" || str == "/")
return 2;
if (str == "+" || str == "-")
return 1;
else
return -1;
}
public double applyOperator(double left, String op, double right) {
if (op == "+") {
return (left + right);
}
if (op == "-") {
return (left - right);
}
if (op == "*") {
return (left * right);
}
if (op == "/") {
return (left / right);
}
if (op == "^") {
return Math.pow(left, right);
} else {
throw new IllegalArgumentException("Not a valid operator");
}
}
public String evaluate(String str)
{
String [] tokens = str.split(" ");
for (int i = 0; i < tokens.length; i++)
{
if (isDouble(tokens [i]) == true)
{
nums.push(Double.parseDouble(tokens [i]));
}
if (tokens [i] == "(")
{
ops.push(tokens [i]);
}
if (tokens [i] == ")")
{
String op1 = ops.pop();
double num1 = nums.pop();
double num2 = nums.pop();
double result = applyOperator(num1,op1,num2);
nums.add(result);
}
if (tokens [i] == "+" || tokens [i] == "-" || tokens [i] == "*" || tokens [i] == "/" || tokens [i] == "^")
{
if(ops.isEmpty())
{
ops.push(tokens [i]);
}
else if (prec(tokens [i]) > prec(ops.peek()))
{
ops.push(tokens [i]);
}
else if (prec(tokens [i]) < prec(ops.peek()) && !ops.isEmpty() && ops.peek() != "(")
{
String ac1 = ops.pop();
double res1 = nums.pop();
double res2 = nums.pop();
double outcome = applyOperator(res1,ac1,res2);
nums.add(outcome);
}
}
}
while(!ops.isEmpty() && nums.size() > 1)
{
String ab = ops.pop();
double bb = nums.pop();
double cb = nums.pop();
double clac = applyOperator(bb,ab,cb);
nums.add(clac);
}
String fix = nums.pop().toString();
return fix;
}
}
Tester:
import javax.swing.JOptionPane;
public class AppforCalc {
public static void main(String [] args)
{
Calculator calc = new Calculator();
String reply = "yes";
String instructions = "Enter a mathematical expression. Separate everything with spaces";
while(reply.equalsIgnoreCase("yes"))
{
String expression = JOptionPane.showInputDialog(instructions);
String ans = calc.evaluate(expression);
reply = JOptionPane.showInputDialog("The solution is " + ans + "Try again?");
}
}
}

The main reason you algorithm fails is due to using == when trying to check for String equality.
In Java, == is a boolean operator which behaves identically for all operands, and checks the equality of the values of the operands. This means that primitives are checked as one might expect, but Strings, which are objects, will result in comparing the memory references of the two Strings, which will result in true only if the two Strings are actually the same String. This means that String equality checks must be done with the equals method.
There are more issues with the behavior of the calculator (algorithmic ones), but those will be easier to identify and fix after handling the String equality checks. One example of an issue that must be fixed is:
while(!ops.isEmpty() && nums.size() > 1)
{
String ab = ops.pop();
double bb = nums.pop();
double cb = nums.pop();
double clac = applyOperator(bb,ab,cb);
nums.add(clac);
}
The operands (bb and cb) are popped from a Stack, therefore they arrive in a reveresed order (when parsed, cb was pushed into the stack before bb). This means that cb is the leftside operand and bb is the rightside operand -> double clac = applyOperator(cb,ab,bb); The same refactoring should be done for all usages of the applyOperand method.
Another issue is the following:
else if (prec(tokens [i]) < prec(ops.peek()) && !ops.isEmpty() && ops.peek() != "(")
{
String ac1 = ops.pop();
double res1 = nums.pop();
double res2 = nums.pop();
double outcome = applyOperator(res1,ac1,res2);
nums.add(outcome);
}
An internal evaluation was made, but the triggering of the evaluation is the discvery of an operand with a lower presendence. The operand should be pushed into the operations stack after the evaluation:
else if (prec(tokens [i]) < prec(ops.peek()) && !ops.isEmpty() && ops.peek() != "(")
{
...
...
nums.add(outcome); // I highly suggest refactoring this to nums.push due to readability considerations
ops.push(tokens[i]);
}
References:
The difference between == and equals in Java
Guide for implementing a scientific calculator (in c++, use as an algorithmic reference)
The Shunting Yard Algorithm - As suggested by user207421

Related

How to use variables in stack?

I'm trying to write a calc program that finds the infix. In addition the user will input numbers for the x variable and the program will solve it. My program works but it only solves it the first time. The following times it gives the same answer as the first time.
import java.util.Scanner;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.LinkedList;
class Stack {
char a[] = new char[100];
int top = -1;
void push(char c) {
try {
a[++top] = c;
} catch (StringIndexOutOfBoundsException e) {
System.out.println("Stack full , no room to push , size=100");
System.exit(0);
}
}
char pop() {
return a[top--];
}
boolean isEmpty() {
return (top == -1) ? true : false;
}
char peek() {
return a[top];
}
}
public class intopost {
static Stack operators = new Stack();
public static void main(String argv[]) throws IOException {
String infix;
// create an input stream object
BufferedReader keyboard = new BufferedReader(new InputStreamReader(
System.in));
// get input from user
System.out.print("\nEnter the algebraic expression in infix: ");
infix = keyboard.readLine();
String postFx = toPostfix(infix);
// output as postfix
System.out.println("The expression in postfix is:" + postFx);
if (postFx.contains("x")) {
String line = "";
do {
System.out.println("Enter value of X : ");
line = keyboard.readLine();
if (!"q".equalsIgnoreCase(line)) {
postFx = postFx.replaceAll("x", line);
System.out.println("Answer to expression : "
+ EvaluateString.evaluate(postFx));
}
} while (!line.equals("q"));
} else {
System.out.println("Answer to expression : "
+ EvaluateString.evaluate(postFx));
}
}
private static String toPostfix(String infix)
// converts an infix expression to postfix
{
char symbol;
String postfix = "";
for (int i = 0; i < infix.length(); ++i)
// while there is input to be read
{
symbol = infix.charAt(i);
// if it's an operand, add it to the string
if (symbol != ' ') {
if (Character.isLetter(symbol) || Character.isDigit(symbol))
postfix = postfix + " " + symbol;
else if (symbol == '(')
// push (
{
operators.push(symbol);
} else if (symbol == ')')
// push everything back to (
{
while (operators.peek() != '(') {
postfix = postfix + " " + operators.pop();
}
operators.pop(); // remove '('
} else
// print operators occurring before it that have greater
// precedence
{
while (!operators.isEmpty() && !(operators.peek() == '(')
&& prec(symbol) <= prec(operators.peek()))
postfix = postfix + " " + operators.pop();
operators.push(symbol);
}
}
}
while (!operators.isEmpty())
postfix = postfix + " " + operators.pop();
return postfix.trim();
}
static int prec(char x) {
if (x == '+' || x == '-')
return 1;
if (x == '*' || x == '/' || x == '%')
return 2;
return 0;
}
}
class EvaluateString {
public static int evaluate(String expression) {
char[] tokens = expression.toCharArray();
// Stack for numbers: 'values'
LinkedList<Integer> values = new LinkedList<Integer>();
// Stack for Operators: 'ops'
LinkedList<Character> ops = new LinkedList<Character>();
for (int i = 0; i < tokens.length; i++) {
// Current token is a whitespace, skip it
if (tokens[i] == ' ')
continue;
// Current token is a number, push it to stack for numbers
if (tokens[i] >= '0' && tokens[i] <= '9') {
StringBuffer sbuf = new StringBuffer();
// There may be more than one digits in number
while (i < tokens.length && tokens[i] >= '0'
&& tokens[i] <= '9')
sbuf.append(tokens[i++]);
values.push(Integer.parseInt(sbuf.toString()));
}
// Current token is an opening brace, push it to 'ops'
else if (tokens[i] == '(')
ops.push(tokens[i]);
// Closing brace encountered, solve entire brace
else if (tokens[i] == ')') {
while (ops.peek() != '(')
values.push(applyOp(ops.pop(), values.pop(), values.pop()));
ops.pop();
}
// Current token is an operator.
else if (tokens[i] == '+' || tokens[i] == '-' || tokens[i] == '*'
|| tokens[i] == '/') {
// While top of 'ops' has same or greater precedence to current
// token, which is an operator. Apply operator on top of 'ops'
// to top two elements in values stack
while (!ops.isEmpty() && hasPrecedence(tokens[i], ops.peek()))
values.push(applyOp(ops.pop(), values.pop(), values.pop()));
// Push current token to 'ops'.
ops.push(tokens[i]);
}
}
// Entire expression has been parsed at this point, apply remaining
// ops to remaining values
while (!ops.isEmpty())
values.push(applyOp(ops.pop(), values.pop(), values.pop()));
// Top of 'values' contains result, return it
return values.pop();
}
// Returns true if 'op2' has higher or same precedence as 'op1',
// otherwise returns false.
public static boolean hasPrecedence(char op1, char op2) {
if (op2 == '(' || op2 == ')')
return false;
if ((op1 == '*' || op1 == '/') && (op2 == '+' || op2 == '-'))
return false;
else
return true;
}
// A utility method to apply an operator 'op' on operands 'a'
// and 'b'. Return the result.
public static int applyOp(char op, int b, int a) {
switch (op) {
case '+':
return a + b;
case '-':
return a - b;
case '*':
return a * b;
case '/':
if (b == 0)
throw new UnsupportedOperationException("Cannot divide by zero");
return a / b;
}
return 0;
}
There is a mistake inside while loop in main method. See snippet below.
postFx = postFx.replaceAll("x", line);
System.out.println("Answer to expression : "
+ EvaluateString.evaluate(postFx));
Here postFx = postFx.replaceAll("x", line); you lost reference to postfix form that contains variable x. Subsequent calls of replaceAll doesn't have any effect. So expression with first entered value is evaluated.
You can easily fix it by replacing code above with
System.out.println("Answer to expression : "
+ EvaluateString.evaluate(postFx.replaceAll("x", line)));

Why isn't this program running properly? [duplicate]

This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 7 years ago.
The assignment was to create a postfix to infix converter using Stacks. The program compiles properly but when I tried to make a demo class, I received a null point exception line 32. Please share any observations, better coding conventions, or solutions.
import java.util.Stack;
public class PostfixtoInfix {
private String expression;
private Stack<Character> s;
Character pOpen = new Character('(');
Character pClose = new Character(')');
public String PostfixtoInfix(String e) {
expression = e;
String output = "";
for (int i = 0; i < e.length(); i++) {
char currentChar = e.charAt(i);
if (isOperator(currentChar)) {
while (!s.empty() && s.peek() != pOpen
&& hasHigherPrecedence(s.peek(), currentChar)) {
output += s.peek();
s.pop();
}
s.push(currentChar);
} else if (isOperand(currentChar)) {
output += currentChar;
} else if (currentChar == '(') {
s.push(currentChar);
} else if (currentChar == ')') {
while (!s.empty() && s.peek() != pClose) {
output += s.peek();
s.pop();
}
}
while (!s.empty()) {
output += s.peek();
s.pop();
}
}
return output;
}
public boolean isOperator(char c) {
if (c == '+' || c == '-' || c == '/' || c == '*' || c == '^')
return true;
return false;
}
public boolean isOperand(char c) {
if (c >= '0' && c <= '9')
return true;
if (c >= 'a' && c <= 'z')
return true;
if (c >= 'A' && c <= 'Z')
return true;
return false;
}
public int getOperatorWeight(char operator) {
int weight = -1;
switch (operator) {
case '+':
case '-':
weight = 1;
break;
case '*':
case '/':
weight = 2;
break;
case '^':
weight = 3;
}
return weight;
}
public boolean hasHigherPrecedence(char operator1, char operator2) {
int op1 = getOperatorWeight(operator1);
int op2 = getOperatorWeight(operator2);
if (op1 == op2) {
if (isRightAssociative(operator1))
return false;
else
return true;
}
return op1 > op2 ? true : false;
}
public boolean isRightAssociative(char op) {
if (op == '^')
return true;
return false;
}
}
To fix the NPE initialize your objects. Unlike C++, Stack<Character> s; is equivalent to Stack<Character> s = null;; not to Stack<Character> s = new Stack<>();!
Beware of == and != not behaving as you might expect for boxed objects.
Character a = new Character('A');
Character aa = new Character('A');
System.out.println(a == aa);
gives the (correct!) answer false.
They are different objects. If you want to compare for equality, use either:
System.out.println(a.equals(aa));
System.out.println((char)a==(char)aa);
The first uses an explicit method for comparing the object contents. The second one avoids this problem by using non-object primitives, where equality is bitwise, not reference-equality.
It appears that you declare a private member s, never assign anything to it, and then attempt to use it in expressions like s.empty() and s.pop(). If nothing is ever assigned to s, then it is null, and attempting to call a method on it will result in a NullPointerException.
To create an empty stack, you probably want to change the declaration to:
private Stack <Character> s = new Stack<Character>();
First of all, you have a method looking like a constructor:
public String PostfixtoInfix(String e) {
try changing it to something else, like:
public String transform(String e) {
Second, your s field never gets assigned a stack. Put
s = new Stack<Character>();
in your constructor. Also, new Character('a') != new Character('a'), because that will bypass automatic (pillowweight cached) boxing. Use instead just simple chars as pOpen and pClose.
Your access modifier may be preventing the program to access the stack.
Change:
private Stack <Character> s;
to:
protected Stack <Character> s;
Read more here

How to make a java infix to postfix while including spaces

I am trying to make a java class that allow the user to put in space when putting in the tokens for the calculator and then turns it into postfix.
But it is not giving the correct output. For example, for an input of 1+2, the output should be 12+ but it is 12.
import java.util.*;
public class Infix
{
Stack loco = new Stack();
//create a scanner
//now to create a stack
public String Prefix(String gordo)
{
//Here is where the Program Begin
//type the the regular expression
String[] red;
red=gordo.split("(?=[()+\\-*/])|(?<=[()+\\-*/])"); //tokenize the string include delimiter
System.out.println("THE EXPRESSION IN INFIX IS");
for(int k=0;i<red.length;k++)
{
red[i]=red[i].trim(); //remove white spaces
}
//now we will test out if what is stored is digit or character
System.out.println("BREAKING IT ALL DOWN INTO A STRING OF CHARACTERS");
String ramon;
char[] c; //an array of characters
char feo; // a single character
String post=""; //this is where the post fix expression will be put in
for(int i=0;i<red.length;i++)
{
ramon=red[i];
c=ramon.toCharArray();
for(int j=0;j<c.length;j++)
{
System.out.println(c[j]); //print what is stored in C
feo=c[j];
if(Character.isLetterOrDigit(feo) == true)
{
post=post+feo; //add character to string to post fix
}
else if( feo == '(' )
{
loco.push(feo);
}
else if( feo == ')')
{
char look;
while((look = LookAt()) != '(')
{
post=post+look; //add it all in there
PopIt();
}
}
//this does the associtivity and the operator precdence
//if the operator is lower or equal to the precedence change
//the current operand pop it from stack and put it into output
//string
else
{
while(LaPrio(feo) <= LaPrio(LookAt()))
{
post=post+LookAt();
PopIt();
}
}
}
}
System.out.println("THIS IS THE POSTFIX EXPRESSION");
return post;
}
//this will determine operator precedence
private int LaPrio(char operator)
{
if(operator == '/' || operator == '*' || operator == '%')
{
return 2;
}
if(operator == '+' || operator == '-')
{
return 1;
}
return 0;
}
//this will do the see what is one top of the stack
private Character LookAt()
{
if( !loco.empty() == false) //if there no items it will return false plus ! make it true
{
return(Character) loco.peek();
}
else
return 0;
}
private void PopIt()
{
if(!loco.empty())
{
loco.pop();
}
}
}

Arithmetic calculation for BODMAS in Java

I have written this code for Bodmas, but getting some error in this. If I do 3-5+9, it will result in 3.04.0.
It just start concatenating, though it works for all other operations like *, / and -, please help.
public static String calculation(BODMASCalculation bodmas, String result) {
while (bodmas.hasMatch()) {
double value, leftOfOperator = bodmas.getLeft();
char op = bodmas.getOperator();
double rightOfOprator = bodmas.getRight();
switch (op) {
case '/':
if(rightOfOprator == 0) //Divide by 0 generates Infinity
value = 0;
else
value = leftOfOperator / rightOfOprator;
break;
case '*':
value = leftOfOperator * rightOfOprator;
break;
case '+':
value = leftOfOperator + rightOfOprator;
break;
case '-':
value = leftOfOperator - rightOfOprator;
break;
default:
throw new IllegalArgumentException("Unknown operator.");
}
result = result.substring(0, bodmas.getStart()) + value + result.substring(bodmas.getEnd());
bodmas = new BODMASCalculation(result);
}
return result;
}
Another function is:-
public boolean getMatchFor(String text, char operator) {
String regex = "(-?[\\d\\.]+)(\\x)(-?[\\d\\.]+)";
java.util.regex.Matcher matcher = java.util.regex.Pattern.compile(regex.replace('x', operator)).matcher(text);
if (matcher.find()) {
this.leftOfOperator = Double.parseDouble(matcher.group(1));
this.op = matcher.group(2).charAt(0);
this.rightOfOprator = Double.parseDouble(matcher.group(3));
this.start = matcher.start();
this.end = matcher.end();
return true;
}
return false;
}
I have a solution by adding
String sss = null;
if(op == '+' && !Str.isBlank(result.substring(0, bodmas.getStart())) && value >= 0)
sss = "+";
else
sss = "";
result = result.substring(0, bodmas.getStart()) + sss + value + result.substring(bodmas.getEnd());
But don't want to do that, I want this to work for all the operators.
import java.util.Stack;
public class EvaluateString
{
public static int evaluate(String expression)
{
char[] tokens = expression.toCharArray();
// Stack for numbers: 'values'
Stack<Integer> values = new Stack<Integer>();
// Stack for Operators: 'ops'
Stack<Character> ops = new Stack<Character>();
for (int i = 0; i < tokens.length; i++)
{
// Current token is a whitespace, skip it
if (tokens[i] == ' ')
continue;
// Current token is a number, push it to stack for numbers
if (tokens[i] >= '0' && tokens[i] <= '9')
{
StringBuffer sbuf = new StringBuffer();
// There may be more than one digits in number
while (i < tokens.length && tokens[i] >= '0' && tokens[i] <= '9')
sbuf.append(tokens[i++]);
values.push(Integer.parseInt(sbuf.toString()));
}
// Current token is an opening brace, push it to 'ops'
else if (tokens[i] == '(')
ops.push(tokens[i]);
// Closing brace encountered, solve entire brace
else if (tokens[i] == ')')
{
while (ops.peek() != '(')
values.push(applyOp(ops.pop(), values.pop(), values.pop()));
ops.pop();
}
// Current token is an operator.
else if (tokens[i] == '+' || tokens[i] == '-' ||
tokens[i] == '*' || tokens[i] == '/')
{
// While top of 'ops' has same or greater precedence to current
// token, which is an operator. Apply operator on top of 'ops'
// to top two elements in values stack
while (!ops.empty() && hasPrecedence(tokens[i], ops.peek()))
values.push(applyOp(ops.pop(), values.pop(), values.pop()));
// Push current token to 'ops'.
ops.push(tokens[i]);
}
}
// Entire expression has been parsed at this point, apply remaining
// ops to remaining values
while (!ops.empty())
values.push(applyOp(ops.pop(), values.pop(), values.pop()));
// Top of 'values' contains result, return it
return values.pop();
}
// Returns true if 'op2' has higher or same precedence as 'op1',
// otherwise returns false.
public static boolean hasPrecedence(char op1, char op2)
{
if (op2 == '(' || op2 == ')')
return false;
if ((op1 == '*' || op1 == '/') && (op2 == '+' || op2 == '-'))
return false;
else
return true;
}
// A utility method to apply an operator 'op' on operands 'a'
// and 'b'. Return the result.
public static int applyOp(char op, int b, int a)
{
switch (op)
{
case '+':
return a + b;
case '-':
return a - b;
case '*':
return a * b;
case '/':
if (b == 0)
throw new
UnsupportedOperationException("Cannot divide by zero");
return a / b;
}
return 0;
}
// Driver method to test above methods
public static void main(String[] args)
{
System.out.println(EvaluateString.evaluate("10 + 2 * 6"));
System.out.println(EvaluateString.evaluate("100 * 2 + 12"));
System.out.println(EvaluateString.evaluate("100 * ( 2 + 12 )"));
System.out.println(EvaluateString.evaluate("100 * ( 2 + 12 ) / 14"));
}
}
The Java Scripting API allows you to pass parameters from Java application to the script engine and vice versa.
You can use Javax ScriptEngine to pass values from your app to a script.
And using it's eval() method, you can give it a mathematical expression in the form of a string and it will do the the math for you... (Handles BODMAS too).
Example:
ScriptEngineManager mgr = new.ScriptEngineManager();
ScriptEngine engine = mgr.getEngineByName("JavaScript");
String foo = "40+2/3*45";
System.out.println(engine.eval(foo));
Outputs: 70
Include the following imports , if the IDE doesn't suggest them :
import javax.script.ScriptEngineManager;
import javax.script.ScriptEngine;
import javax.script.ScriptException;
Check the documentation here ScriptEngine
I hope it helps.
The solution can be achieved by using the shunting yard algorithm. We start by creating an infix notation of the equation then follows the postfix notation. Here is a description of the algorithm https://en.wikipedia.org/wiki/Shunting_yard_algorithm. This solution solves for any nested number of brackets on the string expression.
public static double evaluate(String exp) {
char[] tokens = exp.toCharArray();
Queue<Object> values = new LinkedList<>();
// Stack for Operators: 'ops'
Stack<Character> ops = new Stack<Character>();
for (int i = 0; i < tokens.length; i++) {
//infix
// Current token is a whitespace, skip it
if (tokens[i] == ' ') {
continue;
}
// Current token is a number, push it to stack for numbers
else if (tokens[i] >= '0' && tokens[i] <= '9') {
StringBuffer sbuf = new StringBuffer();
// There may be more than one digits in number
while (i < tokens.length && tokens[i] >= '0' && tokens[i] <= '9') {
sbuf.append(tokens[i]);
if ((i+1)<tokens.length &&tokens[i + 1] >= '0' && tokens[i + 1] <= '9') {
i++;
} else {
break;
}
}
values.add(Double.parseDouble(sbuf.toString()));
} else if (tokens[i] == '*' || tokens[i] == '-' || tokens[i] == '/' || tokens[i] == '+') {
if (ops.isEmpty()) {
ops.push(tokens[i]);
continue;
}
char op1 = ops.peek();
boolean hasHighPrecedence = hasPrecedence(op1, tokens[i]);
if (hasHighPrecedence) {
char op = ops.pop();
values.add(op);
ops.push(tokens[i]);
} else {
ops.push(tokens[i]);
}
} else if (tokens[i] == '(') {
ops.push(tokens[i]);
} else if (tokens[i] == ')') {
while (ops.peek() != '(') {
values.add(ops.pop());
}
ops.pop();
}
}
while (!ops.isEmpty()) {
values.add(ops.pop());
}
//post fix
Stack<Double> numStack = new Stack<>();
while (!values.isEmpty()) {
Object val = values.poll();
if (val instanceof Character) {
char v = (Character) val;
if (v == '*' || v == '-' || v == '/' || v == '+') {
double num2, num1;
num1 = numStack.pop();
num2 = numStack.pop();
double ans = applyOp(v, num1, num2);
numStack.push(ans);
}
} else {
double num = (double) val;
numStack.push(num);
}
}
return numStack.pop();
}
public static double applyOp(char op, double b, double a) {
switch (op) {
case '+':
return a + b;
case '-':
return a - b;
case '*':
return a * b;
case '/':
if (b == 0)
throw new
IllegalArgumentException("Cannot divide by zero");
return a / b;
}
return 0;
}
public static boolean hasPrecedence(char op1, char op2) {
if (op1 == '*' && op2 == '/') {
return false;
} else if (op1 == '/' && op2 == '*') {
return true;
} else if ((op1 == '*' || op1 == '/') && (op2 == '+' || op2 == '-')) {
return true;
} else if (op1 == '+' && op2 == '-') {
return true;
} else {
return false;
}
}
"BODMAS" is a not very operational rule. Especially addition and subtraction have the same precedence and are calculated from left to right 1-2+3-4+5 = (((1-2)+3)-4)+5.
The rule is for a nested loop.
Loop
replaceAll ( number ) --> number
replaceAll number `[*/]' number --> number op number
replaceAll number `[+-]' number --> number op number
Until nothing is replaced.
This ensures that 3-4/26+5 -2-> 3-26+5 -2-> 3-12+5 -3-> -9+5 -3-> -4

String equation error checker not working

I have a method that checks to see if an equation written is correct.
This method check for:
Multiple Parentheses
Excess operators
Double Digits
q's
and any character in a string that is not and of these:
.
private static final String operators = "-+/*%_";
private static final String operands = "0123456789x";
It was working fine, but then I added in modular to the operators and now whenever my code reaches the part in the method that checks to the left and the right of an operand to see if it is neither the end of the string or the beginning I get an error saying
Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String index out of range: 3
My method and all it's additional methods.
private static final String operators = "-+/*%_";
private static final String operands = "0123456789x";
public Boolean errorChecker(String infixExpr)
{
char[] chars = infixExpr.toCharArray();
StringBuilder out = new StringBuilder();
for (int i = 0; i<chars.length; i++)
{
System.out.print(infixExpr.charAt(i));
if (isOperator(infixExpr.charAt(i)))
{
if (i == 0 || i == infixExpr.length())
{
out.append(infixExpr.charAt(i));
}
else if (isOperator(infixExpr.charAt(i + 1)) && isOperator(infixExpr.charAt(i - 1)))
{
System.out.println("To many Operators.");
return false;
}
else if (isOperator(infixExpr.charAt(i + 1)))
{
if (infixExpr.charAt(i) != '-' || infixExpr.charAt(i + 1) != '-')
{
System.out.println("To many Operators.");
return false;
}
}
else if (isOperator(infixExpr.charAt(i - 1)))
{
if (infixExpr.charAt(i) != '-' || infixExpr.charAt(i - 1) != '-')
{
System.out.println("To many Operators.");
return false;
}
}
}
else if (isOperand(infixExpr.charAt(i)))
{
if (i == 0 || i == infixExpr.length())
{
out.append(infixExpr.charAt(i));
}//THE LINE RIGHT BELOW THIS COMMENT THROWS THE ERROR!!!!!
else if (isOperand(infixExpr.charAt(i + 1)) || isOperand(infixExpr.charAt(i - 1)))
{
System.out.println("Double digits and Postfix form are not accepted.");
return false;
}
}
else if (infixExpr.charAt(i) == 'q')
{
System.out.println("Your meow is now false. Good-bye.");
System.exit(1);
}
else if(infixExpr.charAt(i) == '(' || infixExpr.charAt(i) == ')')
{
int p1 = 0;
int p2 = 0;
for (int p = 0; p<chars.length; p++)
{
if(infixExpr.charAt(p) == '(')
{
p1++;
}
if(infixExpr.charAt(p) == ')')
{
p2++;
}
}
if(p1 != p2)
{
System.out.println("To many parentheses.");
return false;
}
}
else
{
System.out.println("You have entered an invalid character.");
return false;
}
out.append(infixExpr.charAt(i));
}
return true;
}
private boolean isOperator(char val)
{
return operators.indexOf(val) >= 0;
}
private boolean isOperand(char val)
{
return operands.indexOf(val) >= 0;
}
My main portion that runs the method:
Boolean meow = true;
while(meow)
{
System.out.print("Enter infix expression: ");
infixExpr = scan.next();//THE LINE RIGHT BELOW THIS COMMENT THROWS THE ERROR!!!!!
if(makePostfix.errorChecker(infixExpr) == true)
{
System.out.println("Converted expressions: "
+ makePostfix.convert2Postfix(infixExpr));
meow = false;
}
}
It was working fine before, but now it won't even pass 1+2 which was previously working and I changed NONE of that you see. What's wrong!?!?
What looks like what's happening is that you check for the character at index (i + 1) several times in your code. Lets say you input a string with a length of five characters. The program goes through and reaches the line:
else if (isOperator(infixExpr.charAt(i + 1)) && isOperator(infixExpr.charAt(i - 1)))
If i == 4, this will cause the code:
infixExpr.charAt(i + 1)
to throw an index error.
In essance, you're checking for a character at index five (the sixth character) in a string with a maximum index index of four which is five characters in length. Also, your checking for
if(i==0 || i == infixExpr.length)
won't work as is. Maybe check for (i==infixExpr.length-1).

Categories