Why does my comparison clause always throw an IllegalArgumentException? - java

I'm trying to create a calculator method and I want to use mathematical symbols in my case statement but my error checking keeps throwing an error.
I've tried moving my ELSE statements to the bottom in case it was an issue with sequencing somehow. When I add the variable to the end of my error message it appears to assign it correctly.
public static void calculator (double firstNumber, char operation, double secondNumber){
if (operation != '+' || operation != '-' || operation != '*' || operation != '/' || operation !='%'){
throw new IllegalArgumentException("You must choose a number between 1 and 5 inclusive." + operation);
}else{
if(operation == '/' && secondNumber == 0){
throw new IllegalArgumentException("Dividend cannot be zero.");
}else{if(operation == '%' && secondNumber == 0){
throw new IllegalArgumentException("Dividend cannot be zero.");
}else
switch (operation){
case '+': System.out.println("1");
break;
case '-': System.out.println("2");
break;
case '*': System.out.println("3");
break;
....
Example of errors using +, %, and /:
> java.lang.IllegalArgumentException: You must choose a number between 1
> and 5 inclusive.+ at MathUtilites.calculator(MathUtilites.java:39)
> java.lang.IllegalArgumentException: You must choose a number between 1
> and 5 inclusive.% at MathUtilites.calculator(MathUtilites.java:39)
> java.lang.IllegalArgumentException: You must choose a number between 1
> and 5 inclusive./ at MathUtilites.calculator(MathUtilites.java:39)
I am expecting it to just return a number between 1 and 5 which I will later be replacing with actual code.

Like the first comment on your question suggested, you need to replace || with && which will say all of these must be true instead of saying any of these must be true. Alter your code to look like this and it should work:
if (operation != '+' && operation != '-' && operation != '*' && operation != '/' && operation !='%'){
throw new IllegalArgumentException("You must choose a number between 1 and 5 inclusive." + operation);

if (operation != '+' || operation != '-' || operation != '*' || operation != '/' || operation !='%'){
throw new IllegalArgumentException("You must choose a number between 1 and 5 inclusive." + operation);
should be
if (operation != '+' && operation != '-' && operation != '*' && operation != '/' && operation !='%'){
throw new IllegalArgumentException("You must choose a number between 1 and 5 inclusive." + operation);
}
You should look up the boolean algebra related to OR and AND operators.

Related

Whаt is happening here?

Rules for valid Indian mobile number:
The number should contain 10 or 11 or 12 digits.
If it contains 10 digits, then the first digit should be 7 or 8 or 9.
If it contains 11 digits, then the first digit should be 0 and the second rule followed.
If it contains 12 digits, then the first two digits should be 91 and the second rule followed.
For test case:
1
881906355596
this code should produce Invalid but it is showing Valid.
import java.util.*;
import java.lang.*;
import java.io.*;
class GFG
{
public static void main (String[] args)
{
Scanner scan = new Scanner(System.in);
int t=scan.nextInt();
while((t--)!=0){
String s = scan.next();
int length = s.length();
if((length==10) &&((s.charAt(0)=='7')||(s.charAt(0)=='9')||(s.charAt(0)=='8')))
System.out.println("Valid");
else if((length==11) &&(s.charAt(0)=='0')&&(s.charAt(0)=='7')||(s.charAt(0)=='9')||(s.charAt(0)=='8'))
System.out.println("Valid");//code
else if((length==12) &&(s.charAt(0)=='9')&&(s.charAt(1)=='1'))
System.out.println("Valid");//code
else System.out.println("Invalid");
}
}
}
Your second and third conditions are wrong.
The second condition incorrectly returns true for your 881906355596 input.
You'll see why if you arrange it as follows:
else if (
(length==11) && // false &&
(s.charAt(0)=='0') && // false &&
(s.charAt(0)=='7') || // false ||
(s.charAt(0)=='9') || // false ||
(s.charAt(0)=='8') // true
) // equals true
It should be:
else if (length == 11 && s.charAt(0) == '0' && (s.charAt(1) == '7' || s.charAt(1) == '9' || s.charAt(1) == '8'))
The third condition should be:
else if (length == 12 && s.charAt(0) == '9' && s.charAt(1) == '1' && (s.charAt(2) == '7' || s.charAt(2) == '9' || s.charAt(2) == '8'))
You missed one whole ()
else if((length==12) &&((s.charAt(0)=='9')&&(s.charAt(1)=='1')))

Logical OR does not work properly in the while loop

The problem is that, the first condition in the while loop does not get executed at all even if its true. If i remove the Logical OR from the while loop and just write the first condition (selection.compareToIgnoreCase("O") >0) it works fine. But if there are two conditions with Logical OR, it does not work.
I've tried using equals(), I've also tried to negate the logic using
while(!selection.equals("O") || !selection.equals("E")). The second condition works fine but the first does not work at all.
public class OddsOrEvens {
public static Scanner sc = new Scanner(System.in);
public static void main(String[] args){
System.out.println("Let’s play a game called \"Odds and Evens\"");
System.out.println("Whats your name ? ");
String name = sc.nextLine();
System.out.println("Hi "+ name +", which do you choose? (O)dds or (E)vens?");
String selection = sc.nextLine();
System.out.println("selection: " + selection);
while (selection.compareToIgnoreCase("O") >0 || selection.compareToIgnoreCase("E") >0){
System.out.println("Please enter the correct choice. Select 'O' for odds or 'E' for evens");
selection = sc.next();
}
if(selection.equalsIgnoreCase("O")){
System.out.println(name + " has picked Odds! The computer will be evens.");
}else if (selection.equalsIgnoreCase("E")){
System.out.println(name + " has picked Evens! The computer will be Odds.");
}
}
}
Your string comparison is not correct. Compareto returns -1/0/1 for less/equal/greater.
A clearer way to do this is to use toUppercase().equals(....
while (!selection.toUpperCase().equals("O") && !selection.toUpperCase().equals("E")){
That is for not to hold for two cases, one needs !... && ! ... An OR || would have the effect of being always true, as at least one of the cases is false. Alternatively !(... || ...).
while (!selection.equalsIgnoreCase("O") && !selection.equalsIgnoreCase("E")) {
Let's simplify:
!(n == 1) || !(n == 2) // WRONG
n != 1 || n != 2 // WRONG
will always be true, as either n == 1 is false or n == 2 is false: at most one choice can be true, falsifying the others. So on at least on side is !false, true, so the entire expression is true.
!(n == 1) && !(n == 2) // GOOD
n != 1 && n != 2 // GOOD
The mental mistake is that the linguistic OR mostly means EXCLUSIVE OR.
Possible would have been the equivalent:
!(n == 1 || n == 2) <=> n != 1 && n != 2 [De Morgan's law]

Infix to Postfix

I am trying to convert infix to postfix.For example :
"20 + 2 * 3 + (2*8 + 5)* 4" ->20 2 3 * + 2 8 * 5 + 4 * +
here is my code :
Stack<Character> s = new Stack<Character>();
String postfix = "";
boolean enter = true;
String infixExpr = "20 + 2 * 3 + (2*8 + 5)* 4";
for(int i = 0;i<infixExpr.length();i++){
if(Character.isDigit(infixExpr.charAt(i)) == true){
postfix = postfix + infixExpr.charAt(i);
}
if(infixExpr.charAt(i) == '+' || infixExpr.charAt(i) == '-'){
if(s.isEmpty() == true){
s.push(infixExpr.charAt(i));
}
else{
if(s.peek() == '*' || s.peek() == '/' || s.peek() == '+' || s.peek() == '-'){
while(s.isEmpty()== false){
postfix = postfix + s.pop();
}
s.push(infixExpr.charAt(i));
}
else{
s.push(infixExpr.charAt(i));
}
}
}
if(infixExpr.charAt(i) == '*' || infixExpr.charAt(i) == '/' ){
if(s.isEmpty() == true){
s.push(infixExpr.charAt(i));
}
else{
if(s.peek()== '+' || s.peek() == '-' || s.peek() == '('){
s.push(infixExpr.charAt(i));
}
else if(s.peek() == '*' || s.peek() == '/'){
while(s.isEmpty()== false){
postfix = postfix + s.pop();
}
s.push(infixExpr.charAt(i));
}
}
if(infixExpr.charAt(i) == '('){
s.push(infixExpr.charAt(i));
}
if(infixExpr.charAt(i) == ')'){
while(enter){
if(s.peek() == '('){
enter = false;
}
else{
postfix = postfix + s.pop();
}
}
}
}
}
As it is written at the top I suppose to get "20 2 3 * + 2 8 * 5 + 4 * +" but I get "2023*+28*+54" which is wrong and I revised the code many times and still I cant see the problem. It would be great if anybody could help.
Spaces
You are not putting any spaces on your postfix variable. You are only checking if the current character is one of the "interesting" characters (digits, operators), but not whether it's a space. As a result, if the current character is a space, you just skip it and you don't copy it to the postfix.
Since the only things that you put in the postfix are characters that you have checked, you end up with no spaces at all.
You can solve it like this:
Add a boolean called inNumber, set it to true at first.
Whenever you process a digit, before you add it to postfix, check if inNumber is true. If so, add a space first.
If you have just processed a digit, set inNumber to true.
If you are processing an operator, set inNumber to false.
Whenever you add any operator to the stack, add a space first.
The idea about this inNumber is that digits that all belong to the same number should not have spaces between them. But if the digit is added to postfix after we have processed an operator in the previous round, then it belongs to a new number, so there should be a space there.
So basically, your digit handling code should look like:
if(Character.isDigit(infixExpr.charAt(i)) == true){
if ( ! inNumber ) {
postfix += " ";
}
postfix = postfix + infixExpr.charAt(i);
inNumber = true;
}
And in every if that indicate an operator you should have inNumber = false.
And every place where you add an operator to postfix should look like:
postfix = postfix + " " + s.pop();
Handling parentheses
Your other problem is the handling of ().
First, you put the code that checks for ( and ) inside the if for * and /. Of course, if the character at the i position is * or /, it is not a ( or a ) so this code is never called.
So you should move the if for parentheses outside, to the same level of the if on numbers and operators.
Also, your use of enter is wrong. If you have parenthesis inside parenthesis, like ( 3 + ( 5 + 7 ) ), then at the first ) you will go back all the way to the parenthesis after the 5, which is OK. But then enter will become false and you will not process the external pair correctly. This is also true for (3 + 5 ) * ( 7 + 2 ) because you are not setting enter to true again after the beginning of the program.
Instead of using enter, you should pop what's on the stack and check if it was a (:
if(infixExpr.charAt(i) == '('){
inNumber = false;
s.push(infixExpr.charAt(i));
}
if(infixExpr.charAt(i) == ')'){
inNumber = false;
char popped;
while ( ( popped = s.pop() ) != '(' ) {
postfix = postfix + " " + popped;
}
}
Unpopped operators
Finally, you finish when you completed scanning the input. But at this point you will still have operators waiting on the stack! You have to pop them all and add to postfix. So after the loop you should have:
while ( ! s.isEmpty()) {
postfix += " " + s.pop();
}
Additional remarks:
It would be better and more clear if instead of using all those if statements, you used a switch statement.
There is no point in comparing a boolean expression to true. The proper way to write if (s.isEmpty() == true) is just if (s.isEmpty()), and instead of s.isEmpty() != true use ! s.isEmpty().
You are not doing any syntax checking. I am not sure if that's because this is homework, but in real life you should check that every ( is matched by a ), that every operator has two operands, and also handle negative numbers that may have a - in the beginning.
The issue is that you are not adding spaces. You cannot, however, simply add a space in between each number. You have to make sure the spaces are not being added in between the digits of a whole number. To solve this, I simply added a postfix += " "; after the if(infixExpr.charAt(i) == '+' || infixExpr.charAt(i) == '-')and again after if(infixExpr.charAt(i) == '*' || infixExpr.charAt(i) == '/' ). The logic behind this is that once you encounter an operator, you know that everything before the operator was the number. Now when I run the program, the output is 20 2 3 *+2 8 *+5 4. There are still a few spaces that need to be added between the operators, but I'll let you handle that.
Modified code:
if(infixExpr.charAt(i) == '+' || infixExpr.charAt(i) == '-'){
postfix += " ";
...
if(infixExpr.charAt(i) == '*' || infixExpr.charAt(i) == '/' ){
postfix += " ";
here is my code for your answer
#include<stack>
#include<iostream>
using namespace std;
bool high(char a,char b)
{
if(b==' ')
return true;
else if(a==b)
return false;
else if(a=='/')
return true;
else if(a=='*'&&b!='/')
return true;
else if(b=='/')
return false;
else if(a!='/'&&b=='*')
return false;
else if(b=='-')
return true;
else if(a=='-'&&b!='(')
return false;
else if(b=='(')
return true;
else if(a=='(')
return true;
else if(a==')')
return false;
}
main()
{
int k=0;
string s;
stack<char>s1;
s1.push(' ');
char ch;
while(cin>>ch)
{
if(ch=='(')
{
k=1;
s1.push(ch);}
else if(ch>47&&ch<58)
s.push_back(ch);
else if(high(ch,s1.top()))
s1.push(ch);
else if(!high(ch,s1.top())&&ch!=')')
{
while(!s1.empty()&&!high(ch,s1.top()))
{
s.push_back(s1.top());
s1.pop();
}
s1.push(ch);}
else if(ch==')')
{
while(!s1.empty()&&s1.top()!='(')
{
s.push_back(s1.top());
s1.pop();
}
s1.pop();
k=0;
}
}
while(!s1.empty())
{
s.push_back(s1.top());s1.pop();
}
cout<<s;
}

Validate a string contains only certain characters in java

Ok, what I am trying to do is take a user input in infix notation and translate it to postfix and then evaluate it. I have that already completed.
What I am struggling with, is for the user input I need to validate that it only contains the following: (), 0-9, +, -, *, /, %
Each character will be separated by a space, so here is a potential valid input:
( 3 + 4 ) * 5 / ( 6 - 7 )
I have created an InvalidCharacterException that I wish to throw if the user string contains anything other than those characters.
Here is what an invalid input would look like:
3 - 5 ^ 5
The ^ would be an invalid character and then I would throw new InvalidCharacterException and ask for a new input.
I will also say I have looked at a ton of regex samples, and to be honest I don't understand what they're doing.
EDIT:
Ok, this is what I ended up implementing because I don't really understand anything else. Any advice on a simpler way?
for(int i = 0; i <= infix.length(); i++){
if(infix.charAt(i) == '(' || infix.charAt(i) == ')' || infix.charAt(i) =='+'
|| infix.charAt(i) =='-' ||infix.charAt(i) == '*' ||infix.charAt(i) == '/'
||infix.charAt(i) == '%' ||infix.charAt(i) ==' ' ||infix.charAt(i) == '0'
||infix.charAt(i) == '1' || infix.charAt(i) =='2' || infix.charAt(i) =='3'
||infix.charAt(i) == '4' ||infix.charAt(i) == '5' ||infix.charAt(i) == '6'
||infix.charAt(i) == '7' || infix.charAt(i) =='8' ||infix.charAt(i) == '9'){
}else{
throw new InvalidCharacterException(infix.charAt(i));
}
}
Infix is the variable name of my user input as a StringBuffer.
You can use a Scanner to validate your string:
Scanner scanner = new Scanner(string);
String validationResult = scanner.findInLine("[^0-9()+\\-*\\/%]+");
if (validationResult != null) {
// Invalid character found.
throw new InvalidCharacterException("Invalid character: " + validationResult);
}
The findInLine method returns a String with the characters that match the regex and the regex looks for any character not valid in your validation. The findInLine only returns a non null String when there are any invalid characters in the String.
I would suggest you use a Scanner (for an example) and then loop over each character (in each token) and throw your Exception if your criteria are met (e.g. look at Character.isDigit) or just write your own method to test against acceptable characters (e.g. is char is contained in"()0123456789+-*/%").
In your code this is probably better because it does the same thing.
Btw it probably should be i < infix.length() not <=
for(int i = 0; i < infix.length(); i++){
char x = infix.charAt(i);
if(!(Character.isDigit(x) || x == '/' || x == '*' ||
x == '+'|| x== '-' || x=='%' || x == '\n'))
throw new InvalidCharacterException(x);
/* what you want to do if valid*/
}

calculate a process with operator precedence

I am trying to calculate an arithmetic expression, which is entered as a string (for example, ( 5+4*5-1/8 ), which will give the result 3). I enter an expression and convert it into an array. First; the result will start with the first element and it will change in the loop. But the problem is operator precedence. How can I use the operator presedence in a loop? Here is my code:
import java.util.Scanner;
public class HesapMakinesi {
private char value[];
private int count;
private Scanner str = new Scanner(System.in);
private String process;
HesapMakinesi() {
System.out.print("Enter the process ");
process = str.next();
//System.out.println(islem);
Initializer(process);
}
private void Initializer(String process) {
count = process.toCharArray().length;
value = new char [count];
int i;
System.arraycopy(process.toCharArray(), 0, value, 0, count);
//System.out.println(value);
if(value[0]=='-' || value[0]=='+' || value[0]=='/' || value[0]=='*' || // A process cannot start with an operator
value[count-1]=='-' || value[count-1]=='+' || value[count-1]=='/' || value[count-1]=='*') {
System.out.println("You have entered a wrong process.Please enter again!!!");
System.out.print("Enter the process: ");
process = str.next();
Initializer(process);
}
for(i=0; i<count; i++) { // A process cannot include a character except operators
if( value[i]!='+' && value[i]!='-' && value[i]!='*' && value[i]!='/' && value[i]!='(' && value[i]!=')' && !Character.isDigit(value[i]) ) {
System.out.println("You have entered a wrong process.Please enter again!!!");
System.out.print("Enter the process: ");
process = str.next();
Initializer(process);
}
}
for(i=0; i<count-1; i++) { // A process cannot have operators sequantially
if( !Character.isDigit(value[i]) && !Character.isDigit(value[i+1]) ) {
if( (value[i] == '+' && value[i+1] == '+' ) || (value[i] == '+' && value[i+1] == '-' ) || (value[i] == '+' && value[i+1] == '*' ) ||
(value[i] == '+' && value[i+1] == '/' ) ) {
System.out.println("You have entered a wrong process.Please enter again!!!");
System.out.print("Enter the process: ");
process = str.next();
Initializer(process);
}
else if( (value[i] == '-' && value[i+1] == '+' ) || (value[i] == '-' && value[i+1] == '-' ) || (value[i] == '-' && value[i+1] == '*' ) ||
(value[i] == '-' && value[i+1] == '/' ) ) {
System.out.println("You have entered a wrong process.Please enter again!!!");
System.out.print("Enter the process: ");
process = str.next();
Initializer(process);
}
else if( (value[i] == '*' && value[i+1] == '+' ) || (value[i] == '*' && value[i+1] == '-' ) || (value[i] == '*' && value[i+1] == '*' ) ||
(value[i] == '*' && value[i+1] == '/' ) ) {
System.out.println("You have entered a wrong process.Please enter again!!!");
System.out.print("Enter the process: ");
process = str.next();
Initializer(process);
}
else if( (value[i] == '/' && value[i+1] == '+' ) || (value[i] == '/' && value[i+1] == '-' ) || (value[i] == '/' && value[i+1] == '*' ) ||
(value[i] == '/' && value[i+1] == '/' ) ) {
System.out.println("You have entered a wrong process.Please enter again!!!");
System.out.print("Enter the process: ");
process = str.next();
Initializer(process);
}
}
}
//sCount();
}
/*private void Count(){
double result,temp;
int i;
for(i=0; i<count; i++) {
if( value[i]!= )
}
}*/
}
That's not how you do it. You need to parse the expression before evaluating it. I suggest you to read the Shunting-yard algorithm.
Following on from my comment... If you're dealing with a simple expression where you can only have numbers and signs +-/* then you can have a simple approach:
split your expression by lowest precedence operators first (+-) remembering the signs.
Compute each piece - as now the precedence isn't important, since everything is of the same level
sum those computed pieces taking into account the sign of the piece from step 1.
In your example, you'll end up with something like this:
(Split by +-) three pieces: (1) 5; (2) 4*5 with sign +; (3) 1/8 with sign -
Compute each of the three pieces: (1) 5; (2) 20; (3) 0.125
Sum the three pieces with their respective signs: 5+20-0.125 = 24.875

Categories

Resources