I'm learning to code in Java and I'm doing some online exercises where the answer is not explained too much, so I was just curious why my code is incorrect when it seems to be similar to the solution.
The exercise says -
"Given 2 int values, return true if one is negative and one is positive. Except if the parameter "negative" is true, then return true only if both are negative."
public boolean posNeg(int a, int b, boolean negative) {
if (negative && (a < 0 && b < 0)) {
return true;
}
return (a < 0 && b > 0 || a > 0 && b < 0);
} // This is my code that yields unwanted results
public boolean posNeg(int a, int b, boolean negative) {
if (negative) {
return (a < 0 && b < 0);
}
else {
return ((a < 0 && b > 0) || (a > 0 && b < 0));
}
} // This is the solution code
When running posNeg(-4, 5, true); it comes out to be true even though it is supposed to be false. Whenever one int is negative and the other is positive and negative is true, it is supposed to be false but yields true.
public boolean posNeg(int a, int b, boolean negative) {
if (negative && (a < 0 && b < 0)) {
return true;
}
return (a < 0 && b > 0 || a > 0 && b < 0);
} // This is my code that yields unwanted results
Calling posNeg(-4, 5, true); makes the first condition false negative && (a < 0 && b < 0) <===> true && (true && false) <===> false.
Then the run jumps to the end of that if and evaluates the last condition (a < 0 && b > 0) || (a > 0 && b < 0) which is obviously true.
Related
I was wondering how to check if two out of three values are the same. My code right now is:
public static boolean twoOutOfThree(int a, int b, int c) {
if ((a == b) || (b == c) || (a == c)) {
return true;
}
return false;
}
This passes all of the tests that are true however when I test it for (0,0,0), it comes back as true instead of false. Any suggestions on what I'm doing wrong?
When all 3 are the same, then a == b obviously is also true. So each 3 of the cases also needs to check that the 3rd one is different. So you need to change
(a == b || b == c || a == c)
to
(a == b && b != c) || (b == c && a !=c ) || (a == c && b != c))
Additional tip
Functions of this form:
if (condition) {
return true;
} else {
return false;
}
Can be written much shorter by just doing
return condition;
So the end result is this:
public static boolean twoOutOfThree(int a, int b, int c) {
return ((a == b && b !=c ) || (b == c && a !=c ) || (a == c && b !=c));
}
Here is a non-optimized solution.
The Set will get rid of duplicates, then just check its final size.
return new HashSet<Integer>(Arrays.asList(a,b,c)).size() == 2;
You could add an extra case to your if statement:
((a==b) || (b==c) || (a==c) && !(a == b & b == c))
There is probably a more efficient way to do this.
You can add a variable called "count" for example , if any value is equal to another then you increment the count by 1 and then you can check if count is equal to 2
You can count as the following solution
public static boolean twoOutOfThree(int a, int b, int c) {
int count = 0;
if (a == b) {
count += 1;
}
if (b == c) {
count += 1;
}
if (c == a)
count += 1;
}
if (count == 2) {
return true;
} else {
return false;
}
}
Just create a Set and add your values in the set. Set always holds unique values only. So if you have 3 numbers and add them to a set and your set length is 3 that none of the numbers are equal to each other. If the length is 2 then 2 numbers where equal and if the length is 1 then all 3 are equal
return !(
(
(a==b)&&(b==c)
) ||
(
(a!=b)&&(b!=c)&&(a!=c)
)
);
Only 10 operators made of
3 AND
1 OR
1 NOT
5 comparisons
I don't know if this is fastest. But if CPU core has multiple ALUs each doing comparisons in parallel, then this could get a boost.
Currently I am working on a little personal project to help myself learn about coding.
I'm wondering for future reference if I can combine logical operators of different types in a single if statement.
For example if I had
if (n == 0 || n == 1 && m == 0 || m == 1) {
doSomething();
}
Would it check if either parts of the left side are true, then if either parts of the right are true, or would it do something similar to checking if both of the middle ones are true?
Does using parenthesis change anything
For example
if ((n == 0 || n == 1) && (m == 0 || m == 1)) {
doSomething();
}
Edit:
From a suggestion I tried it out, but when i put three variables it started acting weird
Here's my test:
int n = 1;
int m = 1;
int o = 1;
if (n == 0 || n == 1 && m == 0 || m == 1 && o == 0 || o == 1) {
System.out.println("True");
}
else {
System.out.println("False");
}
if ((n == 0 || n == 1) && (m == 0 || m == 1) && (o == 0 || o == 1)) {
System.out.println("True");
}
else {
System.out.println("False");
}
if all of them are 1 or 0, they both evaluate true, if n or m is not 1 or 0 the top evaluates true but the bottom does not.
However if o is not 0 or 1 both of them are false.
I have found that parenthesis do in fact make a difference, but I can't quite tell why it's acting the way it is.
&& has a higher precedence then ||, so n == 0 || n == 1 && m == 0 || m == 1 equals n == 0 || (n == 1 && m == 0) || m == 1. You may check the precedence table here.
I have a use case where I have to check if one condition is subset of another condition. Meaning, the result set that satisfies condition 2 will be the subset of result set that satisfies condition 1.
I was checking and intellij does figures it out during code inspection
if (x < 7 && x > 1) {
return true;
} else if (x > 3 && x <6) {
return false;
}
Here during code inspection it does highlights that result of second condition is always false.
So, How it is implemented?
This range:
(x > 3 && x <6)
is a subrange of:
(x < 7 && x > 1)
so if the condition (x < 7 && x > 1)
is true then this condition (x > 3 && x <6) will not be reached
is false then this condition (x > 3 && x <6) is also false
So the meaning of code inspection is:
if (x > 3 && x <6) is reached then it is always false.
The right way to implement your logic should be to check first the subrange:
if (x > 3 && x <6) {
return false;
} else if (x > 1 && x < 7) {
return true;
} else {
return ....;
}
If I change the else if portion of this code to an else statement it runs without any problems so I get how to make it run. What I'm a little confused about is why I get a missing return statement error when it is in its current form. My return is dependent on the value of the boolean variable of negative. I covered the true and false states, isn't that good enough to cover everything?
Or is it that I always have to have a return statement within an else or to add a meaningless return true to the bottom of my function for the compiler to accept my code as covering every case?
import java.util.*;
import java.lang.*;
import java.io.*;
class Ideone
{
public boolean posNeg(int a, int b, boolean negative) {
if (!negative) {
return (a < 0 && b > 0) || (a > 0 && b < 0);
}
else if (negative) {
return (a < 0 && b < 0);
}
}
public static void main (String[] args) throws java.lang.Exception
{
}
}
When the compiler sees else if without an else or a trailing return statement, it cannot be certain that all control paths will lead to a valid return statement.
The compiler can be smart at times, but it can't be smart in this situation (nor should it be).
This behavior is helpful in your example: there's absolutely no reason for you to use an else if in this situation. A simple else is easier to read, more concise, and less error prone.
An else is very expressive in this case. It means "the opposite of the if clause" which will still be the case if the code changes in the future.
Your current code would be more likely to contain and/or introduce a bug if the compiler allowed it.
Here's how I would rewrite the method body:
if (negative) {
return (a < 0 && b < 0);
}
else {
return (a < 0 && b > 0) || (a > 0 && b < 0);
}
In general you should prefer if (negative) over if (!negative) unless there's a compelling reason (ie readability) to do otherwise.
Also, a lot of people (including myself) try to put the most simple clause first in an if/else statement. Making your code easy to read is a good thing.
Check out StephenC's answer for a technical explanation and more background about why the compiler behaves this way.
Other questions have explained what the error message means from an intuitive perspective. However the "The compiler is smart, but not perfect!" comment is missing the point.
In fact, the Java compiler is calling your example an error because the Java Language Specification requires it to call it an error. The Java compiler is not permitted to be "smart" about this.
Here is what the JLS (for Java 71) actually says, and how it applies to a simplified version of the incorrect example, and then a corrected version.
"If a method is declared to have a return type, then a compile-time error occurs if the body of the method can complete normally (JLS 14.1). In other words, a method with a return type must return only by using a return statement that provides a value return; it is not allowed to "drop off the end of its body". " - JLS 8.4.7
(Read JLS 14.1 for the definition of "normal completion" ...)
And the rules for deciding whether a "normal" completion is possible are the reachability rules in JLS 14.21. And they say:
"An if-then statement can complete normally iff it is reachable."
"An if-then-else statement can complete normally iff the then-statement can complete normally or the else-statement can complete normally."
"A break, continue, return, or throw statement cannot complete normally."
(Where 'iff' means "if and only if" ...)
Consider a simplified version of the example:
public int test(boolean a) {
if (a) {
return 1;
}
else if (!a) {
return 0;
}
}
In this example, the else-statement is an if-then which can complete normally by rule #1. Therefore, by rule #2, the if-then-else statement can also complete normally. But that is a compilation error, because JLS 8.4.7 says that a method with a return type cannot complete normally.
But if you change the example to this ...
public int test(boolean a) {
if (a) {
return 1;
}
else {
return 0;
}
}
Now by rule #3, both the if-statement and the else-statement cannot complete normally. So by rule #2, the entire if-then-else cannot complete normally. That is what it required by JLS 8.4.7 ... therefore no compilation error.
1 - The Java 8 JLS will say essentially the same thing, though the section numbers may be different ...
I think you already know that the second if is redundant.
if (negative) is interpreted context-free, which means that the compiler ignores that if(!negative) has already been handled.
if => else if => where is the else condition?
For a return statement, all branches (conditions) must be handled.
You could do:
if (!negative)
return (a < 0 && b > 0) || (a > 0 && b < 0);
return (a < 0 && b < 0);
or:
if (!negative)
return (a < 0 && b > 0) || (a > 0 && b < 0)
else
return (a < 0 && b < 0);
or (my preferred way):
return negative ? (a < 0 && b < 0) : (a < 0 && b > 0 || a > 0 && b < 0)
However, I'd recommend to avoid the negative condition, it's harder for the human brain in complex scenario. Even some Java IDEs like IntelliJ helps to find those patterns to fix them.
You'd end up with:
if (negative)
return (a < 0 && b < 0);
else
return (a < 0 && b > 0) || (a > 0 && b < 0);
You do not need "if (negative) {}" in the "else" brace
You should have a return in all your branches.
public boolean posNeg(int a, int b, boolean negative) {
if (!negative) {
return (a < 0 && b > 0) || (a > 0 && b < 0);
}
else if (negative) {
return (a < 0 && b < 0);
}
}
The method above logically has a return in all branches, but technically it does not. We like the Java compiler to be fast, therefore it is undesirable to have a Java compiler analyzing semantically the code.
public boolean posNeg(int a, int b, boolean negative) {
if (!negative) {
return (a < 0 && b > 0) || (a > 0 && b < 0);
}
else {
return (a < 0 && b < 0);
}
}
The method above has a return in all the branches.
public boolean posNeg(int a, int b, boolean negative) {
if (!negative) {
return (a < 0 && b > 0) || (a > 0 && b < 0);
}
return (a < 0 && b < 0);
}
However, as you can see above, you do not even need the else, because if the code ever reaches the second return, then negative is certainly false, as if it was true, the first return would end the algorithm.
public boolean posNeg(int a, int b, boolean negative) {
return ((negative) && (a < 0 && b < 0)) || ((!negative) && (a < 0 && b > 0) || (a > 0 && b < 0));
}
The method above is a one-liner.
public boolean posNeg(int a, int b, boolean negative) {
return ((negative) && (a < 0 && b < 0)) || ((!negative) && ((a < 0) == (b > 0)));
}
The method above uses the fact that in the second case the positivity of a is equal with the negativity of b.
if I add or subtract two short values, how can I tell if I would need to flag a carry condition
You can do the addition or subtraction using a larger type such as int, cast it to a short, and test if the cast changes the value.
int i = s1 + s2;
short s = (short)i;
if (i != s) { /* overflow */ }
In the case of adding and subtracting only, arithmetic overflow has occurred when both operands are positive and the result is negative and vice versa.
class OverflowTest
{
public static void main (String[] args)
{
System.out.println(isOverflow((short)32767, (short)32767, '+'));
System.out.println(isOverflow((short)-32767, (short)-32767, '+'));
System.out.println(isOverflow((short)32767, (short)-32767, '+'));
}
private static boolean isOverflow(short a, short b, char op) {
short c = (op == '+') ? (short)(a+b) : (short)(a-b);
if((a > 0 && b > 0 && c < 0) || (a < 0 && b < 0 && c > 0))
return true;
return false;
}
}