I'm trying to make an RPN calculator. I have done the conversion from infix to postfix, now I want to evaluate the converted expression. When I enter any expression I get error
String index out of range: 1.
Here's my code with what I'm supposed to do in the program:
static int eval(String postfix) {
int result = 0;
String temp2 = "";
int num1, num2, OPS;
char operator;
String delete = "";
for (int i = 0; i < postfix.length(); i++) {
char M = postfix.charAt(i);
// if v_i is an operand: Push v_i to tmp2.
if (Character.isDigit(postfix.charAt(i))) {
temp2 = M + temp2;
}
/*
* if v_i is an operator: Apply v_i to the top two elements of tmp2.
* Replace these by the result in tmp2.
*/
if (postfix.charAt(i) == '+' || postfix.charAt(i) == '-' || postfix.charAt(i) == '*'
|| postfix.charAt(i) == '/') {
temp2 = M + temp2.substring(2);
}
while (postfix.charAt(0) != '0') {
num1 = Character.getNumericValue(temp2.charAt(temp2.length()-1));
delete = delete.substring(0,i);
operator = postfix.charAt(i);
num2 = Character.getNumericValue(temp2.charAt(temp2.length()+i));
//Integer.parseInt(postfix.substring(0,i));
result = num1 + num2;
result = num1 - num2;
result = num1 * num2;
result = num1 / num2;
switch (operator) {
case '+':
result = num1 + num2;
break;
case '-':
result = num1 - num2;
break;
case '*':
result = num1 * num2;
break;
case '/':
result = num1 / num2;
break;
}
}
if (temp2.length() != 0) {
temp2 = result + temp2;
}
}
return result;
}
I get the error in this part:
while (postfix.charAt(0) != '0') {
num1 = Character.getNumericValue(temp2.charAt(temp2.length()-1));
delete = delete.substring(0,i);
operator = postfix.charAt(i);
num2 = Character.getNumericValue(temp2.charAt(temp2.length()+i));
//Integer.parseInt(postfix.substring(0,i));
As you can see, I have tried some different string manipulation but they're all incorrect.
My supervisor said something about reading the string from backwards or the last string or something, But I never understood what they meant. Thanks for any help in advance
temp2.charAt(temp2.length()+i)
You are accessing a character of the string with charAt. However temp2 contains temp2.length() characters. Hence you can acces them from index 0 to temp2.length() - 1. Hence accessing the character at position temp2.length()+i is out of range... (for i > 0 !!)
Take a look at your previous one, temp2.charAt(temp2.length()-1).
Here you accessed the last character of the string (at index temp2.length()-1). Any access with a greater index will result in an index out of range.
EDIT : The stop condition of your while loop is while (postfix.charAt(0) != '0'). In the loop you never change the postfix string. Hence if the condition is met (first character of postfix is not '0') you'll have an infinite loop. Hence you'll never reach the return statement.
Change this line
Character.getNumericValue(temp2.charAt(temp2.length()+i));
to
Character.getNumericValue(temp2.charAt(temp2.length()+i-1));
Related
I am new to java and I was learning how to convert from binary to decimal and vice versa. In the case of binary to decimal, I found out that I could use parseint, but I saw other methods that didn't use it, so I tried to implement them into my code, but it didn't work for me and I got stumped.
How would I be able to use a different method for calculating binary to decimal and implement it into my code?
Here is my code:
import java.util.Scanner;
class BinaryToDecimal {
public static void main(String args[]) {
Scanner sc = new Scanner(System.in);
String binaryString;
char choice;
String nextLine = "Empty";
int i = 0;
choice = 'Y';
try {
do {
System.out.print("Enter a binary number: ");
binaryString = sc.nextLine();
//Find the string count
int count = binaryString.length();
for (int j = 0; j< count; j++)
{
if (binaryString.charAt(j) != '1' && binaryString.charAt(j) != '0')
{
System.out.print("Enter a binary number: ");
binaryString = sc.nextLine();
count = binaryString.length();
j=0;
}
}
i = Integer.parseInt(binaryString);
if (i>0)
System.out.println("The decimal number is: " + Integer.parseInt(binaryString, 2));
System.out.println("Continue using the calculator? Only input Y or N");
String ln = sc.next();
if(ln.length()==1){
choice = ln.charAt(0);
}
else{
choice = 'N';
}
if (sc.hasNextLine()) {
nextLine = sc.nextLine();
}
} while (choice == 'Y');
} catch (NumberFormatException nfe) {
System.out.println("Invalid input");
}
}
}
Binary math involves adding 1 and multiplying by 2. I would use a regular expression to test if the input is valid. I would use an infinite loop and break when the user gives an answer besides y when prompted to continue. Putting that together, gives a simplified
Scanner sc = new Scanner(System.in);
while (true) {
System.out.println("Enter a binary number: ");
String binaryString = sc.nextLine();
// An int value consists of up to 32 0 and 1s.
if (!binaryString.matches("[01]+") || binaryString.length() > 32) {
continue;
}
int v = 0;
for (int i = 0; i < binaryString.length(); i++) {
v *= 2;
if (binaryString.charAt(i) == '1') {
v++;
}
}
System.out.println("The decimal number is: " + v);
System.out.println("Continue using the calculator? Only input Y or N");
String ln = sc.nextLine();
if (!ln.equalsIgnoreCase("Y")) {
break;
}
}
It looks like your missing you're missing the radix which the default I use is 2. Try this and let me know what happens
i = Integer.parseInt(binaryString,2);
There may be a nicer way of doing this, however this is the solution that I came up with. I took into account that the number can both be a positive and negative number and added checks for those cases. I also made sure to add exceptions for when an invalid binary number is entered.
public static int numberFromBinary(String binaryNumber) {
char[] array = binaryNumber.toCharArray();
boolean isNegative = false;
int result = 0;
if (array.length > 32) {
throw new NumberFormatException("An integer cannot be more than 32 bits long.");
}
if (array.length == 32) {
isNegative = array[0] == '1';
if (isNegative) {
result -= 1;
}
}
for (int i = 0; i < array.length && i != 31; i++) {
int worth = (int) Math.pow(2, i);
if (array[array.length - 1] != '1' && array[array.length - 1] != '0') {
throw new NumberFormatException("Binary bits can only be a '1' or a '0'.");
}
if (isNegative) {
if (array[array.length - 1] == '0') {
result -= worth;
}
} else {
if (array[array.length - 1] == '1') {
result += worth;
}
}
}
return result;
}
Here's a solution for converting a string representation of a binary number to a decimal number, without using Integer.parseInt(). This is based on
your original question text:
How would I be able to use a different method for calculating binary to decimal and implement it into my code?
And also a comment you added:
Also i did not want to use parseint
If you take a binary number and work your way from right to left, each digit is an increasing power of 2.
0001 = 2^0 = 1
0010 = 2^1 = 2
0100 = 2^2 = 4
1000 = 2^3 = 8
You can follow this same pattern: inspect each character position of a binary string input, and raise 2 to some power to get the decimal value represented by that bit being set to 1. Here's a simple bit of code that:
prompts for user input as a binary string
starting from right and working toward the left, it checks each character, comparing against '1'
if the character is in fact 1: take note of the position, raise 2 to the next power, and add that to the running total
Here's the code:
System.out.print("enter a binary number: ");
String binaryInput = new Scanner(System.in).next();
int decimalResult = 0;
int position = 0;
for (int i = binaryInput.length() - 1; i >= 0; i--) {
if (binaryInput.charAt(i) == '1') {
decimalResult += Math.pow(2, position);
}
position++;
}
System.out.println(binaryInput + " --> " + decimalResult);
And a few sample runs:
enter a binary number: 1111
1111 --> 15
enter a binary number: 101010101
101010101 --> 341
enter a binary number: 100000000000
100000000000 --> 2048
I'm a new java coder getting into it doing a project. I coded it how i believe the system would execute it and yet it doesn't seem to be following the While loops requirements. I want it to generate random number, do a random operation, then ask the user for an answer. The answer must be not decimal and the random numbers must be below 10 to make the questions easier as its for a lower target audience. I'm kind of stuck now on this piece. Apologies if this doesn't make sense as i say it is a first attempt for me.
import java.util.Random;
import java.lang.Math;
import java.util.Scanner;
public class RandomisedQuestions{
public static void QuestionGenerator(){
Random r = new Random();
Scanner s = new Scanner(System.in);
int intA = 0;
int intB = 0;
char operator ='?';
double value = 1.2;
for (int i = 0; i < 3; i++) {
intA = (int)(10.0 * Math.random());//the (int) forces the number to be an int
intB = (int)(10.0 * Math.random());
if (intA <= 0 && intB <= 0){
intA = (int)(10.0 * Math.random());//the (int) forces the number to be an int
intB = (int)(10.0 * Math.random());
System.out.println(intA + intB);
}
while ((value % 1) !=0 && value > 1){//Runs while value is not whole
switch (r.nextInt(4)){
case 0: operator = '+';
value = intA+intB;
break;
case 1: operator = '-';
value = intA-intB;;
break;
case 2: operator = '*';
value = intA*intB;;
break;
case 3: operator = '/';
value = intA/intB;;
break;
default: operator = '?';
}
//System.out.println(operator);
}
System.out.println(intA +""+ operator +""+ intB);
System.out.println("Enter the answer");
int uGuess = s.nextInt();
if (uGuess == value){
System.out.println("Correct");
}
else{
System.out.println("Incorrect");
}
}
}
}
It's better to use ThreadLocalRandom.nextInt to generate your numbers:
// At the start of your program initialize the generator:
ThreadLocalRandom r = ThreadLocalRandom.current();
// Later use it:
do {
intA = ThreadLocalRandom.nextInt(1, 10);
intB = ThreadLocalRandom.nextInt(1, 10);
switch (r.nextInt(4)) {
case 0: operator = '+';
value = intA + intB;
break;
case 1: operator = '-';
value = intA - intB;
break;
case 2: operator = '*';
value = intA * intB;
break;
case 3: operator = '/';
value = (double)intA / intB;
break;
default: operator = '?';
}
} while (value != (int)value || value <= 1);
Also note the conversion to double in division case, otherwise the division will be performed for integer types.
I have a string like: value += 5 * 3 - (2 / 4) for example.
Now I must change all operators to their opposite, so:
+ to -
- to +
* to /
/ to *
My problem is when I use replaceAll() function
First time:
string.replaceAll("+", "-"); I become: value -= 5 * 3 - (2 / 4)
Second time:
string.replaceAll("-", "+"); I become: value += 5 * 3 + (2 / 4)
but it's need to be: value -= 5 * 3 + (2 / 4)
How can I achive that?
You could create a Map with the Characters to replace and iterate through the String like this:
public static void main(String[] args) {
Map<Character, Character> replacers = new HashMap<>();
replacers.put('+', '-');
replacers.put('-', '+');
String value = "value += 5 * 3 - (2 / 4)";
StringBuilder out = new StringBuilder();
for (char c : value.toCharArray()) {
out.append(replacers.getOrDefault(c, c));
}
System.out.println(out.toString());
}
This will print out:
value -= 5 * 3 + (2 / 4)
Why not just loop through string char-by-char and replace single letter at a time to avoid such chaos?
public String revert(String expression){
char[] temp = expression.toCharArray();
for(int i = 0; temp.length> i; i++){
switch(temp[i]){
case '/':
temp[i] = '*';
break;
case '*':
temp[i] = '/';
break;
case '-':
temp[i] = '+';
break;
case '+':
temp[i] = '-';
break;
}
}
return new String(temp);
}
You could first replace your symbols (+,-,...) to some different ones that cannot be present in your expression e.g. +->A, -->B, ... and than all As to -, Bs to +, ... .
Other option is creating array of chars from your string and than iterate this array invert your symbols in situ. and than create String again.
I think a simple loop will work;
String exp="YOUR EXPRESSION HERE";
String newStr="";
//loop through the string
for(int i=0;i<exp.length();i++)
{
char ch=exp.charAt(i);//extract a charcter
switch(ch)
{
case '+':
newExp+='-';// replace + with -
break;
case '-':
newStr+='+';// and - with +
break;
case '*';
newStr+='/'// divide with *
break;
case '/'
newStr+='*';// multiply with /
break;
default:
newStr+=ch;// leave it as it is
}
}
You are probably better off just looping through the values, perhaps in a char array.
String val = "value += 5 * 3 - (2 / 4)";
char[] cArray = val.toCharArray();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < cArray.length; i++) {
if (cArray[i] == '+') {
sb.append("-");
} else if (cArray[i] == '-') {
sb.append("+");
// repeat for others
} else {
sb.append(cArray[i]);
}
}
Output:
value -= 5 * 3 + (2 / 4)
Working on this problem, and also did a few reference to similar solutions. One thing I am confuse is, why we break the loop as long as there is one repetitive number? Is it possible the number repeat for 2-3 times and then changed to another different number? Thanks.
I mean this part specifically,
if (map.containsKey(num)) {
int index = map.get(num);
res.insert(index, "(");
res.append(")");
break;
}
The problem,
Given two integers representing the numerator and denominator of a fraction, return the fraction in string format.
If the fractional part is repeating, enclose the repeating part in parentheses.
For example,
Given numerator = 1, denominator = 2, return "0.5".
Given numerator = 2, denominator = 1, return "2".
Given numerator = 2, denominator = 3, return "0.(6)".
public class Solution {
public String fractionToDecimal(int numerator, int denominator) {
if (numerator == 0) {
return "0";
}
StringBuilder res = new StringBuilder();
// "+" or "-"
res.append(((numerator > 0) ^ (denominator > 0)) ? "-" : "");
long num = Math.abs((long)numerator);
long den = Math.abs((long)denominator);
// integral part
res.append(num / den);
num %= den;
if (num == 0) {
return res.toString();
}
// fractional part
res.append(".");
HashMap<Long, Integer> map = new HashMap<Long, Integer>();
map.put(num, res.length());
while (num != 0) {
num *= 10;
res.append(num / den);
num %= den;
if (map.containsKey(num)) {
int index = map.get(num);
res.insert(index, "(");
res.append(")");
break;
}
else {
map.put(num, res.length());
}
}
return res.toString();
}
}
thanks in advance,
Lin
The code doesn't stop when it sees a digit repeated. It stops when it notes that it has reached a state which it was already in. If it reaches the same state again, it means that we are about to repeat a division that we have already done, which means that the dividend and remainder are going to be the same, and we are going to do the same series of steps we have already done.
When that happens, it means a repetition, and it stops and adds the parentheses.
For example, let's divide 123 by 999. This should give us the repeating decimal 0.123123123..., so the output should be 0.(123).
123 / 999 is 0. The remainder is 123. We start with 0.
Multiply the remainder by 10. Now we have 1230 / 999. Dividend is 1, remainder is 231. Now we have 0.1
Multiply the remainder by 10. Now we have 2310 / 999. Dividend is 2, remainder is 312. Now we have 0.12
Multiply the remainder by 10. Now we have 3120 / 999. Dividend is 3, remainder is 123. Now we have 0.123
Multiply the remainder by 10. Now we have 1230 / 999... wait, we have already done that! That means that as we continue to divide, we'll get to that number again and again. Stop and put parentheses around the repeating part.
The map is there to tell us which numbers we have already divided, and at which index in the StringBuilder. When we find a number we have already divided, we use that index to know where to insert the parenthesis.
Clearly it's possible to have a decimal number with two or more decimals recurring and then a different decimal. For example 449/1000 = 0.449
Here is my solution in Java to this problem:
/**
* Given two integers a and b, return the result as a String.
* Display the repeating part of the fraction in parenthesis.
*
* Runs in O(b)
*
* #author Raed Shomali
*/
public class Divider {
private static final String DOT = ".";
private static final String ERROR = "ERROR";
private static final String LEFT_PARENTHESIS = "(";
private static final String RIGHT_PARENTHESIS = ")";
public static String divide(final int a, final int b){
if (b == 0) {
return ERROR;
}
int value = a / b;
int remainder = a % b;
return String.valueOf(value) + DOT + divider(remainder, b);
}
private static String divider(final int a, final int b) {
final Map<Integer, Integer> remainderIndexMap = new HashMap<>();
final List<Integer> values = new ArrayList<>();
int value;
int remainder = a;
while (!remainderIndexMap.containsKey(remainder)) {
remainderIndexMap.put(remainder, values.size());
remainder *= 10;
value = remainder / b;
remainder = remainder % b;
values.add(value);
}
final int index = remainderIndexMap.get(remainder);
final StringBuilder result = new StringBuilder();
for (int i = 0; i < index; i++) {
result.append(values.get(i));
}
result.append(LEFT_PARENTHESIS);
for (int i = index; i < values.size(); i++) {
result.append(values.get(i));
}
result.append(RIGHT_PARENTHESIS);
return result.toString();
}
}
Basically, the idea is simple. Using the same long division technique, you know when to stop when you have already seen the same remainder value.
Here are some test cases to show a few different scenarios:
divide(0, 0) // "ERROR"
divide(1, 2) // "0.5(0)"
divide(0, 3) // "0.(0)"
divide(10, 3) // "3.(3)"
divide(22, 7) // "3.(142857)"
divide(100, 145) // "0.(6896551724137931034482758620)"
If you are interested in a solution written in Go, you can find it here https://github.com/shomali11/util
This problem is actually very simple to solve if we use the long division technique that we learnt in 4th grade.
Suppose you need to divide 92 by 22. How do you do it using the long division method. How do you detect a repeating pattern?
Simple, you know you have a repeating pattern of decimals when you encounter a previously encountered reminder. You'll need to store the reminders and the corresponding index of the result in a dictionary and using the same you could detect/print repeating decimals. Working python code below.
def divide(numerator, denominator):
sign, res, lead = '', '', ''
if (numerator < 0) ^ (denominator < 0) and numerator != 0:
sign = '-'
numerator = abs(numerator)
denominator = abs(denominator)
remainders = defaultdict(list)
if numerator < denominator:
lead = '0'
_x = str(numerator)
r = 0
i = 0
j = 0
while True:
if i < len(_x):
d = int(str(r)+_x[i])
q = d // denominator
if not (q == 0 and len(res) == 0):
res += str(q)
r = d - (q * denominator)
i += 1
elif i >= len(_x) and j <= 9223372036854775807:
if r == 0:
return sign+lead+res
if j == 0:
remainders[r] = [True, len(res)+1]
res += '.'
d = int(str(r) + '0')
q = d // denominator
res += str(q)
r = d - (q * denominator)
if remainders[r] and remainders[r][0]:
res = res[0:remainders[r][1]] + '(' + res[remainders[r][1]:] + ')'
return sign+lead+res
remainders[r] = [True, len(res)]
j += 1
else:
return sign+lead+res
I'm making a RPN calculator, I have done the part of converting infix to postfix, now I want to evaluate the expression in postfix.
example:
converting from ((3 + 5 1)=8) 14 to 3 5 1 +8 = 14 (I have done that). now evaluating the latter expression.
The instructions I have:
Given a postx expression v 1:::v n,
where v i is either an operand or an operator,
the following algorithm evaluates the expression. A helper string, temp2, is
used during the calculation.
i = 1
while i<= n
if v_i is an operand: Push v_i to tmp2.
if v_i is
an operator: Apply v_i to the top two elements of tmp2. Replace
these by the result in tmp2.
i = i + 1
Output result from tmp2.
My code:
static int eval(String postfix) {
int result = 0;
String temp2 = "";
int num1, num2;
char operator;
for (int i = 0; i < postfix.length(); i++) {
char M = postfix.charAt(i);
// if v_i is an operand: Push v_i to tmp2.
if (Character.isDigit(postfix.charAt(i))) {
temp2 = M + temp2;
}
/*
* if v_i is an operator: Apply v_i to the top two elements of tmp2.
* Replace these by the result in tmp2.
*/
if (postfix.charAt(i) == '+' || postfix.charAt(i) == '-' || postfix.charAt(i) == '*'
|| postfix.charAt(i) == '/') {
temp2 = M + temp2.substring(2);
num1 = Character.getNumericValue(temp2.charAt(temp2.length() - 1));
operator = postfix.charAt(i);
num2 = Character.getNumericValue(temp2.charAt(temp2.length() + i - 1));
switch (operator) {
case '+':
result = num1 + num2;
break;
case '-':
result = num1 - num2;
break;
case '*':
result = num1 * num2;
break;
case '/':
result = num1 / num2;
break;
}
}
}
return result;
}
I get
Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String index out of range: 2
at:
num2 = Character.getNumericValue(temp2.charAt(temp2.length() + i - 1));