I need help with evaluating arithmetic expression (INFIX) via recursion. I made a tree, scanning from right to left (+,- first, *,/ second). The error is:
For input string: "2+3"
I don't what I'm doing wrong. I was hoping if someone can look at my method and point me to right direction please. Appreciate the help. Here is my method.
// recursive method to evaluate an expression given by string s
int evaluateE(String s)
{
String r1;
String r2;
int result = 0;
int i;
for(i = s.length() - 1; i >= 0; i--)
{
if (s.charAt(i) == '+' || s.charAt(i) == '-')
break;
else if (s.charAt(i) == '*' || s.charAt(i) == '/')
break;
}
r1 = s.substring(0, i);
r2 = s.substring(i + 1, s.length());
//Base case
if(!r1.contains("+") && !r1.contains("-") && !r1.contains("*") && !r1.contains("/") &&
!r2.contains("+") && !r2.contains("-") && !r2.contains("*") && !r2.contains("/"))
return Integer.parseInt(s);
switch (s.charAt(i))
{
case '+':
result = evaluateE(r1) + evaluateE(r2);
break;
case '-':
result = evaluateE(r1) - evaluateE(r2);
break;
case '*':
result = evaluateE(r1) * evaluateE(r2);
break;
case '/':
if (Integer.parseInt(r2) == 0) //if denominator is zero
{
System.out.println("Invalid divisor");
System.exit(1);
}
else
result = evaluateE(r1) / evaluateE(r2);
break;
}
return result;
}
You're checking the operators, if they contain an operator, i.e. for r1+r2 you check, if r1 or r2 contain a operator. If your String contains exactly 1 operator, neither r1 nor r2 contain a operator and therefore Integer.parse(s) will be executed. Since s = r1 + operator + r2 contains the operator, Integer.parse will throw an error.
To fix this, check the base case before doing anything else in that method:
int evaluateE(String s) {
//Base case
if (!s.contains("+") && !s.contains("-") && !s.contains("*") && !s.contains("/")) {
return Integer.parseInt(s);
}
int i;
for (i = s.length() - 1; i >= 0; i--) {
if (s.charAt(i) == '+' || s.charAt(i) == '-') {
break;
} else if (s.charAt(i) == '*' || s.charAt(i) == '/') {
break;
}
}
String r1 = s.substring(0, i);
String r2 = s.substring(i + 1, s.length());
int result = 0;
switch (s.charAt(i)) {
case '+':
result = evaluateE(r1) + evaluateE(r2);
break;
case '-':
result = evaluateE(r1) - evaluateE(r2);
break;
case '*':
result = evaluateE(r1) * evaluateE(r2);
break;
case '/':
int right = evaluateE(r2);
if (right == 0) //if denominator is zero
{
System.out.println("Invalid divisor");
System.exit(1);
} else {
result = evaluateE(r1) / right;
}
break;
}
return result;
}
That ignores operator precedence however, i.e. it evaluates expressions from left to right. E.g. 10-3*6/9+4 is interpreted as (((10-3)*6)/9)+4.
If you want to take operator precedence into accout, you have to ignore * or /, if there is a + or a - in the string. This would require you to modify your for loop:
// search for '+' and '-' first
for (i = s.length() - 1; i >= 0; i--) {
if (s.charAt(i) == '+' || s.charAt(i) == '-') {
break;
}
}
if (i < 0) {
// if '+' and '-' were not found, search for '*' and '/'
for (i = s.length() - 1; i >= 0; i--) {
if (s.charAt(i) == '*' || s.charAt(i) == '/') {
break;
}
}
}
It is not clear why you are returning Integer.parseInt(s) when in all likelihood s will have an operator (+,-,* or /). So, essentially you are trying to convert "2+3" into an int, which is the reason for the error.
Related
Hey' all so im figuring out how to multiply bigintegers without importing them and I have it almost all. The only thing that isnt working is when multiplying with -digit the output is still +. any help appreciated. ie. -20*4=80
Scanner scan = new Scanner(System.in);
System.out.println("Type the first number:");
String x = scan.nextLine();
System.out.println("Type the second number:");
String y = scan.nextLine();
if (x.charAt(0) == '-' && y.charAt(0) != '-') {
x = x.substring(1);
}
else if (x.charAt(0) != '-' && y.charAt(0) == '-') {
y = y.substring(1);
}
else if (x.charAt(0) == '-' && y.charAt(0) == '-') {
x = x.substring(1);
y = y.substring(1);
}
String s1 = new StringBuffer(x).reverse().toString();
String s2 = new StringBuffer(y).reverse().toString();
int[] m = new int[s1.length() + s2.length()];
for (int i=0; i<s1.length(); i++) {
for (int j=0; j<s2.length(); j++) {
m[i+j] = m[i+j] + (s1.charAt(i) - '0') * (s2.charAt(j) - '0');
}
}
String product = new String();
for (int i=0; i<m.length; i++) {
int digit = m[i] % 10;
int carry = m[i] / 10;
if (i+1 < m.length) {
m[i+1] = m[i+1] + carry;
}
product = digit + product;
}
while (product.length() > 1 && product.charAt(0) == '0') {
product = product.substring(1);
}
if (x.charAt(0) == '-' && y.charAt(0) != '-') {
product = new StringBuffer(product).insert(0, '-').toString();
}
else if (x.charAt(0) != '-' && y.charAt(0) == '-') {
product = new StringBuffer(product).insert(0, '-').toString();
}
else if (x.charAt(0) == '-' && y.charAt(0) == '-') {
product = product;
}
System.out.println("The multiplication of\n" + x + " \nand\n" + y + " " + "\nis\n" + product);
scan.close();
}
}
You're removing the negative symbol from the numbers here:
if (x.charAt(0) == '-' && y.charAt(0) != '-') {
x = x.substring(1);
}
else if (x.charAt(0) != '-' && y.charAt(0) == '-') {
y = y.substring(1);
}
So after those lines your x and y variables no longer contain the negative symbol.
So when you're checking it near the end here:
if (x.charAt(0) == '-' && y.charAt(0) != '-') {
product = new StringBuffer(product).insert(0, '-').toString();
}
else if (x.charAt(0) != '-' && y.charAt(0) == '-') {
product = new StringBuffer(product).insert(0, '-').toString();
}
else if (x.charAt(0) == '-' && y.charAt(0) == '-') {
product = product;
}
It will never get into any of the conditions.
One good way to debug this on your end is to set a breakpoint within the condition you think it should drop into and see if it's hit. Or breakpoint before the conditions and examine the variables to ensure they are what you expect them to be. You could also throw some println statements in there temporarily just to say "I got into this conditional".
The adjustment I'd recommend making is holding onto whether each number was negative before stripping the negative so you can use that in your logic later on.
Here's the adjustment which should accomplish what you want. I used Integers instead of bools to make the check for whether to apply the negative symbol later easier (i.e. isFirstNumberNegative + isSecondNumberNegative == 1)
Scanner scan = new Scanner(System.in);
System.out.println("Type the first number:");
String x = scan.nextLine();
System.out.println("Type the second number:");
String y = scan.nextLine();
// hold onto which numbers are negative
Integer isFirstNumberNegative = x.charAt(0) == '-' ? 1 : 0;
Integer isSecondNumberNegative = y.charAt(0) == '-' ? 1 : 0;
// strip the negative symbols from the numbers which are negative
if (isFirstNumberNegative > 0) {
x = x.substring(1);
}
if (isSecondNumberNegative > 0) {
y = y.substring(1);
}
String s1 = new StringBuffer(x).reverse().toString();
String s2 = new StringBuffer(y).reverse().toString();
int[] m = new int[s1.length() + s2.length()];
for (int i=0; i<s1.length(); i++) {
for (int j=0; j<s2.length(); j++) {
m[i+j] = m[i+j] + (s1.charAt(i) - '0') * (s2.charAt(j) - '0');
}
}
String product = new String();
for (int i=0; i<m.length; i++) {
int digit = m[i] % 10;
int carry = m[i] / 10;
if (i+1 < m.length) {
m[i+1] = m[i+1] + carry;
}
product = digit + product;
}
while (product.length() > 1 && product.charAt(0) == '0') {
product = product.substring(1);
}
// if only one number is negative put a negative symbol in front
// if both numbers are negative this condition won't hold true because it will be == 2
// if both numbers are positive this condition won't hold true because it wil be == 0
if (isFirstNumberNegative + isSecondNumberNegative == 1) {
product = new StringBuffer(product).insert(0, '-').toString();
}
System.out.println("The multiplication of\n" + x + " \nand\n" + y + " " + "\nis\n" + product);
scan.close();
Just remove the symbols from the numbers and save them. Then later, use them to determine if a negative is required. An exclusive or test for - is all that is necessary for a negative result.
You can create a record (or a class) to return the numbers and resulting sign, ready for processing.
record Numb(String sign,String num1, String num2) {}
String n1 = "-2123";
String n2 = "+2343";
Numb n = prepNums(n1,n2);
System.out.println(n.sign + ", " + n.num1 + " " + n.num);
Prints
-, 2123, 2343
After multiplying, just prepend the sign to the result. Note that the default positive sign is no sign.
And here is the method that processes the strings and returns
them and the resultant sign for multiplication.
public static Numb prepNums(String n1, String n2) {
boolean sign1 = false;
boolean sign2 = false;
char firstChar = n1.charAt(0);
if (!Character.isDigit(firstChar)) {
sign1 = firstChar == '-';
n1 = n1.substring(1); // remove sign
}
firstChar = n2.charAt(0);
if (!Character.isDigit(firstChar)) {
sign2 = firstChar == '-';
n2 = n2.substring(1); // remove sign
}
return new Numb( (sign1 ^ sign2) ? "-" : "", n1, n2);
}
just speaking in a generic concept sense - the square root of largest safe unsigned int,
4^3^3/2-1
is approx 94906265.6242. So right off the bat you know you don't have 8-full decimal digits width to work with unless you add in special tricks.
All those fancy algorithms they talk about - they frequently waste your time by having to first convert from decimal to binary, do the math, then re-convert it back out.
I just split mine into chunks of 7-digits wide, so the the maximum multiply result per op is capped at just shy of 10^14
- for 7 9's squaring each other, approx. 46.50699304-binary bits
- for 8 9's squaring ………. is approx. 53.15084949 bits
for whatever slowness one might believe in simpleton grade school multiply, you more than gain back the savings by avoiding a bidirectional base-conversion.
The examples look like this, Input : "a-(b+c)" output "a-b-c", Input : "a-(a+b)" output "b"
I came up with this method, but the result for input: "a-(a+b)" is "a-a-b", which the correct one should be "b", how to improve that?
public String simplify(String str)
{
int len = str.length();
char res[] = new char[len];
int index = 0, i = 0;
Stack<Integer> s = new Stack<Integer> ();
s.push(0);
while (i < len) {
if (str.charAt(i) == '+') {
if (s.peek() == 1)
res[index++] = '-';
// If top is 0, append the same operator
if (s.peek() == 0)
res[index++] = '+';
} else if (str.charAt(i) == '-') {
if (s.peek() == 1)
res[index++] = '+';
else if (s.peek() == 0)
res[index++] = '-';
} else if (str.charAt(i) == '(' && i > 0) {
if (str.charAt(i - 1) == '-') {
// x is opposite to the top of stack
int x = (s.peek() == 1) ? 0 : 1;
s.push(x);
}
else if (str.charAt(i - 1) == '+')
s.push(s.peek());
}
else if (str.charAt(i) == ')')
s.pop();
else
res[index++] = str.charAt(i);
i++;
}
return new String(res);
}
I'd need some help with Java here...
I have to implement a DFA in Java that recognizes Java comments contained between /* and */.
In order to start with simple things, let's say that DFA's alphabet is: {'/', '*', 'a'}, so it recognizes only those 3 elements.
Possible accepted Strings:
1) /**/
2) /****/
3) /*a*a**/
4) /*a**/
It won't accept:
1) /*/
2) /**/***/
In order to achieve that I developed this method:
public static boolean scan(String s){
int i = 0, state = 0;
while(i < s.length() && stato >= 0){
final char ch = s.charAt(i++);
switch(state){
case 0:
if(ch == '/')
state = 1;
else
state = -1;
break;
case 1:
if(ch == '*')
state = 2;
else
state = -1;
break;
case 2:
if(ch == 'a')
state = 2;
else if(ch == '/')
state = 3;
else
state = -1;
break;
case 3:
if(ch == '*')
state = 4;
else
state = -1;
break;
case 4:
if(ch == ' ')
state = 4;
else
state = -1;
break;
}
}
System.out.println("State: " + state);
return state == 4;
}
But with simplest input /**/ status variable is -1, when it should be 4.
Which changes should I make?
Hope you guys can help me...
Thank you
In Step 3 your state became -1. then how you get matching.
See this block:
case 2:
if(ch == 'a')
state = 2;
else if(ch == '/')
state = 3;
else
state = -1;
break;
State 0 : char / : nextState 1
State 1 : char * : nextState 2
State 2 : char * : nextState -1
State -1 : char / : nextState -1
I've wrote a method/function in Java which returns the result of a given basic equation. This equation will be given as a String and I think I got this method working but don't know why I need this one line of Code because this should work without it. After trying for more than an hour to solve it I gave up and hope you can give me an aswer.
Here the Code:
public static double format(String s) {
char[] c = s.toCharArray();
if(s.contains("(")) {
int openbrackets = 0;
for (int i = 0; i < s.length() - 2; i++) {
if (c[i] == '(') openbrackets++;
else if (c[i] == ')') {
openbrackets--;
if(openbrackets == 0) {
s = s.replace(s.substring(s.indexOf('('), i+1), ""+(format(s.substring(s.indexOf('(')+1, i))));
break;
}
}
}
}
if (s.contains("(")) { // String can still contains brackets
s = "" + format(s);
}
c = s.toCharArray();
for(int i = c.length-1; i >= 0; i--) {
if(c[i] == '+') {
return format(s.substring(0, i)) + format(s.substring(i+1, s.length()));
} else if(c[i] == '-') {
return format(s.substring(0, i)) - format(s.substring(i+1, s.length()));
}
}
for(int i = s.length()-1; i > 0; i--) {
if(c[i] == '*') {
return format(s.substring(0, i)) * Double.parseDouble(s.substring(i+1, s.length()));
} else if (c[i] == '/') {
return format(s.substring(0, i)) / Double.parseDouble(s.substring(i+1, s.length()));
}
}
return s.equals("") ? 0 : Double.parseDouble(s); // I don't understand why I need to do this line
}
Description:
I don't know why I need this s.equals("") ? : because the String never should be empty however when I run it with this equation ((23)+(23-23-432-35-1-2-4231+2312+12323-(-3))*3/2) for example I get an error without it.
I need the parser to convert config Strings into Numbers for example when it comes to screenresolution. I know I can also use Libraries but I want to try these things by myself.
PS: Dont hate me just because I don't use libraries. I really tried to figure it out and I have fun doing it. I would just like to know why I have to write this little Codeline as I don't figure it out...
Edit: Error was a NumberFormatException as the Parsing got an empty String... Got my error now also the OverflowException which was mentioned in the comments...
EDIT: To everyone who MIGHT use something like this in the future:
Here the Code which actually works:
public static double format(String s) {
s = s.replace(" ", "");
s = s.replace("\t", "");
char[] c = s.toCharArray();
if(s.contains("(")) {
int openbrackets = 0;
for (int i = 0; i < s.length(); i++) {
if (c[i] == '(') openbrackets++;
else if (c[i] == ')') {
openbrackets--;
if(openbrackets == 0) {
s = s.replace(s.substring(s.indexOf('('), i+1), ""+(format(s.substring(s.indexOf('(')+1, i))));
break;
}
}
}
}
if (s.contains("(")) s = "" + format(s);
c = s.toCharArray();
for(int i = c.length-1; i > 0; i--) {
if(c[i] == '+') {
return format(s.substring(0, i)) + format(s.substring(i+1, s.length()));
} else if(c[i] == '-') {
return format(s.substring(0, i)) - format(s.substring(i+1, s.length()));
}
}
for(int i = s.length()-1; i > 0; i--) {
if(c[i] == '*') {
return format(s.substring(0, i)) * Double.parseDouble(s.substring(i+1, s.length()));
} else if (c[i] == '/') {
return format(s.substring(0, i)) / Double.parseDouble(s.substring(i+1, s.length()));
}
}
return s.equals("") ? 0 : Double.parseDouble(s);
}
I'm fairly sure this is at least one location in your code where you pass a 0 length string to your format function:
c = s.toCharArray();
for(int i = c.length-1; i >= 0; i--) {
if(c[i] == '+') {
return format(s.substring(0, i)) + format(s.substring(i+1, s.length()));
} else if(c[i] == '-') {
return format(s.substring(0, i)) - format(s.substring(i+1, s.length()));
}
}
Your loop counter in (int i = c.length-1; i >= 0; i--) will get decremented until it is 0 in value if there are no + or - values in the input string.
Then you call format(s.substring(0, i)) where i = 0 so I think this is one place where you will be passing a zero length/empty string to your function.
Please use a debugger and step through your code - not only would it teach you a valuable skill it would also probably give you the answer you're looking for.
I try to make an long if-statement more compact; this is how it is originaly:
char x;
if(list.size()== 1){
x = 'a';
}
if(list.size()== 2){
x = 'b';
}
if(list.size() == 3){
x = 'c';
}
if(list.size() == 4){
x= 'd';
}
Is there a possibility to compact this code?
thanks already,
Jari Van M
As a first step, we refactor the code to an if-else cascade and backup the list size we are going to use often:
1:
int size = list.size();
char x;
if(size == 1) {
x = 'a';
} else if(size == 2) {
x = 'b';
} else if(size == 3) {
x = 'c';
} else if(size == 4) {
x = 'd';
} else {
//undefined
x = '\0';
}
As we compare the list size with constants only in this case, we can further transform this into a switch statement:
2:
char x;
switch (list.size()) {
case 1: x = 'a'; break;
case 2: x = 'b'; break;
case 3: x = 'c'; break;
case 4: x = 'd'; break;
//undefined
default: x = '\0'; break;
}
Assuming this isn't a randomly chosen example but real code, we see that we need a function which takes a number starting from 1 which outputs the alphabet ('a' to 'z') with increasing value:
3:
char x;
if(list.isEmpty()) {
//undefined
x = '\0';
} else {
//our function
x = (char) ('a' + list.size() - 1);
if(x > 'z') {
//undefined
x = '\0';
}
}
You are basically mapping the size to a character. It can be done easier:
x = 'a' + list.size() - 1;
Easier Option:
Use switch case.
Tricker Option:
char x = (char) ('a' + list.size() - 1);
char x;
int size = list.size();
if (size >= 1 && size <= 4) {
x = "zabcd".charAt(size);
}