Java: weird behavior of conditional operator - java

I have a very simple java class to solve Decode ways using recursive approach. I am seeing this weird behavior of conditional operator,
package decodeways;
public class Solution {
public static void main(String[] args) {
System.out.println(numDecodings("1456"));
}
public static int numDecodings(String s) {
if(s.length()>0 && s.charAt(0)=='0')
return 0;
if(s.length()==0) return 1;
if(s.length()==1)
return 1;
int num1 = s.charAt(0)-'0';
int num2 = s.charAt(1)-'0';
int one = numDecodings(s.substring(1));
int two = s.length()>1?numDecodings(s.substring(2)):0;
int res = one
+ num1<3 && num2<7 ? two:0;
return res;
}
}
if I put a parentheses, (num1<3 && num2<7 ? two:0) then everything is well and good but if I remove the parentheses, then getting incorrect results.
during the process of debugging, one will be computed to 1 and two will be computed to 1 and res will be 1 as well with parentheses but without it, the computed result of res will be 0 (screnshot attached) which is the source of error.
I am aware of the operator precedence in java, but in this situation I can't figure out why it shows incorrect behavior, because in the below code:
int res = one
+ num1<3 && num2<7 ? two:0;
one + num1<3 is illegal
So, java is intelligent enough to not confuse between (one + num1<3) and (num2<7 ? two:0) to be consider separately.
So, as per my understanding the only legal observable behavior for java compiler is to automatically consider num1<3 && num2<7 ? two:0 as an atomic operation(Please correct me if I am wrong), irrespective of parentheses is available or not.
Please guide me to have a better understanding.
Thanks.

int res = one
+ num1<3 && num2<7 ? two:0;
is equivalent to
int res = (((one + num1) < 3) && (num2 < 7)) ? two : 0;
Everything before ? is included in the boolean expression, since the ternary/conditional operator has the lowest precedence here (not including the assignment operator) and + has the highest.
The order goes something like:
+, so one + num1 is put together first
<, so now there's (one + num1) < 3 and num2 < 7
&&, after which you have ((one + num1) < 3) && (num2 < 7)
and finally ?:
You seem to be expecting the newline to make the compiler think one and num1<3 && num2<7 ? two:0 are separate, but it actually just ignores all whitespace. Putting the parentheses there is the only way to make sure one is added to the whatever the conditional operator evaluates to.
int res = one + (num1 < 3 && num2 < 7 ? two : 0);

Related

Turn Positive into negative?

I've got this code
public class FiboNegativV {
int negativ(int nv) {
if (nv ==0)
return 1;
if (nv ==1)
return 2;
return negativ(nv-1) + negativ(nv-2);
}
}
Now I would like to turn the final number into negative. I've tried a few things like "nv = -nv;" But I usually got stackover when I put it before the
"return negativ(nv-1) + negativ(nv-2)" and it is unreachable when it's after this line.
You don't need function for that just do it like this:
int x *= -1;
All the other answers for some reason disregard your initial intention of a Fibbonacci sequence. But I do not understand why they do not keep the context. Your method obviously tries to do a Fibbonacci sequence with recursion yielding negative numbers.
Now I would like to turn the final number into negative.
The simplest and most intuitive way of negatinv a number is to use a unary minus operator = just add a minus before the expression (so negating x to -x). We use this only on positive numbers, so that the negative ones stay negative: (note: this is a ternary operator)
(result > 0) ? -result : result;
However the big mistake is that you do NOT handle negative numbers in the recursive method in the first place! Of course you run into stack overflow, because the recursive negative numbers are going to get lower and lower.
static int negativFib(int nv)
{
//turn negative input into positive
nv = nv < 0 ? -nv : nv;
//base cases
if (nv == 0)
return 1;
if (nv == 1)
return 2;
final int result = negativFib(nv - 1) + negativFib(nv - 2);
//turn the number into negative
return result > 0 ? -result : result;
}
Alternative algorithm
An another problem which could occur is that with big numbers, the recursion comes to a stack overflow. You could prevent this by using some other algorithm, f.e. dynamic programming. With dynamic programming Fibbonacci sequence you store the previous 2 results every time and solve the problem in iterations, instead of recursion.
If you only want to convert positive into negative then
nv = (nv > 0) ? nv * -1 : nv
if you want to convert positive to negative and negative to positive then
nv = nv * -1
Below your code will look like
public class FiboNegativ
{
public FiboNegativV(){}
int negativ(int nv)
{
return (nv > 0) ? nv*-1 : nv;
}
}
Since you want only the final number to be negative, the easiest way is to work with absolute numbers, and return negative numbers, as per the following:
public class FiboNegativV {
int negativ(int nv) {
return (nv == 0) ? -1 :
(nv == 1) ? -2 :
-(Math.abs(negativ(nv-1)) + Math.abs(negativ(nv-2)));
}
}
The assumption I have made, above, is that the initial input to the function will always be positive. Your original code confirms this assumption.
-1 * (Math.abs(negativ(nv-1) + negativ(nv-2)));
Thus the result will be negative regardless of the values given.

Invalid assignment operator in Java

I'm running a super basic program for my class on Java with eclipse, the point of it to write a for loop that prints odd number from 1 to 99 (inclusive) and I'm writing my code
int num1 = 1;
int num2 = 99;
for (num1 => num2 ;; num1 + 2)
System.out.println(num1);
and it's telling me that + and >= are invalid AssignmentOperators. Why is it doing this?
You have several problems there. The first is you should write <= rather than =>. The second is you put the loop condition in the wrong place (it should be between the two semicolons). And lastly you're not assigning new values to num1 (so it never increases).
In addition, you don't need num2 (although it's not a mistake to use it, it makes it a bit less clear).
The final code should look like this:
int num1 = 1;
for (num1 = 1; num1 <= 99; num1 += 2)
System.out.println(num1);
Plus, I'm pretty sure you're coding in Java and not JavaScript (they're two different things).
Firstly there is no necessity of defining data type in Javascript.
That being said you do not need int num1 or num2.
This answer is valid if you are using Javascript not JAVA
Instead can be done this way
for (i = 1; i < 99 ; i++){
if(i%2 !== 0){
console.log(i);
}else{}
}

Java program terminating without error?

I'm trying to make a program that finds the largest palindrome that is a product of two 3-digit numbers. This is what I have right now (I am new to programming):
int num1 = 0;
int num2 = 0;
int product = 0;
int tempProd1 = 0;
int tempProd2 = 0;
int tempProd3 = 0;
int tempProd4 = 0;
int tempProd5 = 0;
int tempProd6 = 0;
String prodCheck1 = "";
String prodCheck2 = "";
while (num1 < 1000){
while (num2 < 1000){
product = num1 * num2;
prodCheck1 = Integer.toString(product);
tempProd1 = product % 10;
product = product / 10;
tempProd2 = product % 10;
product = product / 10;
tempProd3 = product % 10;
product = product / 10;
tempProd4 = product % 10;
product = product / 10;
tempProd5 = product % 10;
product = product / 10;
tempProd6 = product % 10;
product = product / 10;
prodCheck2 = "tempProd1" + "tempProd2" + "tempProd3" + "tempProd4" + "tempProd5" + "tempProd6";
if (prodCheck1 == prodCheck2){
System.out.println(prodCheck1);
}
num2++;
}
num1++;
}
Thing is, every time I try to run it, it terminates without an error. Could someone explain what I'm doing wrong?
Edit: Thanks everyone, finally fixed it. The answer is 853358, if anyone was wondering.
Edit: Actually, the number was 906609.
One thing I noticed immediately is that after the first iteration of the inner loop, num2 is 1000 and so the inner loop will just do nothing in the remaining 999 iterations of the outer loop. You have to reset num2 to 0.
Also consider using "for" loops instead; they're designed to prevent this kind of mistake:
for (int num1=0; num1<1000; num1++) {
...
}
Another problem is that the palindrome check is wrong. You cannot compare Strings with == (it tests for object identity, not string equality -- you'd have to use equals() instead). But even that is wrong because prodCheck2 is "tempProd1tempProd2..." and doesn't contain the actual numbers. The easiest way to check for a palindrome would be:
if (tempProd1 == tempProd6 && tempProd2 == tempProd5 && tempProd3 == tempProd$) {
...
}
Equals method for strings
There are several issues here. First == should not be used to compare strings. You should use string.equals(otherString);
Contatinating words
Second you appear to be combining words when you want to combine values
prodCheck2 = "tempProd1" + "tempProd2" + "tempProd3" + "tempProd4" + "tempProd5" + "tempProd6;
will give
prodCheck2 = "tempProd1tempProd2tempProd3tempProd4tempProd5tempProd6";
always. The fact that those words happen to have the same name as some of your variables makes no difference to java.
There are many better ways to concatenate integers. But the easiest is probably as follows
prodCheck2 = tempProd1 + "" + tempProd2 + "" +tempProd3 + "" +tempProd4 + "" +tempProd5 + "" +tempProd6";
Using while when for would be better
while (num1 < 1000){
while (num2 < 1000){
......
num2++;
}
num1++;
}
This code never decreases num2, which means num2 goes 1->1000 for num1=0 and then stays at 1000 from then on. I'm guessing this isn't what you want. We could fix the while loop but really this is what a for loop is for
for(int num1=0;num1<1000;num1++){
for(int num2=0;num2<1000;num2++){
//code as before, no need to inciment or reset num1 or num2 inside the loop
}
}
Issues that don't break your code
You're declaring all your variables with very large scope. For example tempProd1 is declared outside all the loops depite only being needed inside the inner loop. Declare variables in the smallest scope possible. This will catch bugs like those we've found here. Critically num2 couldn't have accidently been made non resetting if you'd delared it within the first loop
if (prodCheck1 == prodCheck2){
System.out.println(prodCheck1);
}
is a comparison that is based solely on the identity equality of prodCheck1 and prodCheck2. Rewrite that code as:
if (prodCheck1.equals()){
System.out.println(prodCheck1);
}
to use value equality that will return true for identical strings.

Atoi in Java for negative values

I am writing an Atoi function in Java. It runs fine for +ve integers. But what I want is when I enter a negative integer it should give me an error. So I tried including continue statement in my class Atoi. The class implemented is:
class Atoi {
int atoi(String tmp) {
int result = 0;
for (int i = 0; i < tmp.length(); i++) {
char digit = (char)(tmp.charAt(i) - '0');
if(digit == '-')
continue;
}
else {
result += (digit * Math.pow(10, (tmp.length() - i - 1)));
}
return result;
}
}
But unfortunately it gives me the negative equivalent of the character i.e for -12 it gives me 655312! Help.
EDIT: Suppose I need to check for floating point numbers what should I do? If I enter 12.1 or 123.2 it should return 12.1 and 123.2 repectively!!
Instead of continue you should give an error (throw an exception, return -1 or whatever you mean with "give an eror").
If you want to ignore the - you can change the else clause to:
result = digit + result * 10;
Quick fix for the obvious problem: the order of the logic was wrong...
Instead of
char digit = (char)(tmp.charAt(i) - '0');
if(digit=='-')
continue;
try
char origChar=tmp.charAt(i);
if(origChar=='-')
continue;
char digit = (char)(origChar - '0');
But there are two more problems:
it does not negate the value, in case of a '-' character is present!
what if this is the input string: -1-2-3-4-5? The result will be interesting! EDIT: try this input also: 'répa'... Even more interesting result!
Don't forget to test with incorrect inputs too, and as #Klaus suggested, don't hesitate to throw an exception, (preferably IllegalArgumentException) with a correct error message, if an incorrect input is given to the function...
If this is not being done as a programming exercise, there is a simpler solution:
static int atoi(String tmp)
{
int result = Integer.parseInt(tmp);
if(result >= 0) {
return result;
} else {
throw new IllegalArgumentException("Negative string "+"\"" + tmp + "\"");
}
}
Substitute the appropriate exception or other action in the negative result case. If you want to just ignore '-', as in the posted code, replace the if-then-else with:
return Math.abs(result);
This code also throws an exception for strings like "abc".
More generally, if a library method does not do exactly what you want, it is often easy to use it in a method that modifies its behavior, rather than re-writing it.
You can write code like this, of course, but you need to check that tmp is a valid number.
int atoi(String tmp) {
int result = 0;
int factor = tmp.charAt(0) == "-" ? -1 : 1;
for (int i = 0; i < tmp.length(); i++) {
if (tmp.chatAt(i) < '0' || tmp.chatAt(i) > '9')
continue;
char digit = (char)(tmp.charAt(i) - '0');
result += (digit * Math.pow(10, (tmp.length() - i - 1)));
}
return result * factor;
}
if(digit=='-')
With
(char)(tmp.charAt(i)
You're code is assuming there are no -'s
(char)(tmp.charAt(i) - '0');
Is an optimization that's blindly clamping the 'digit' variable to a number.
You need to step through what your code is actually doing, search for an ASCII chart and work through what the subtractions of '0' does ('0' == 48), so '1' (49) - '0' (48) = 1 etc...
If you don't want to convert negative numbers then simply return 0 whenever you encounter - sign instead of looping further. Put this code before the if-else block.
if(tmp.charAt(i)=='-')
return 0;

Efficient implementation for: "Python For Else Loop" in Java

In Python there is an efficient for .. else loop implementation described
here
Example code:
for x in range(2, n):
if n % x == 0:
print n, 'equals', x, '*', n/x
break
else:
# loop fell through without finding a factor
print n, 'is a prime number'
In Java I need to write more code to achieve the same behavior:
finishedForLoop = true;
for (int x : rangeListOfIntegers){
if (n % x == 0)
{
//syso: Some printing here
finishedForLoop = false
break;
}
}
if (finishedForLoop == true){
//syso: Some printing here
}
Is there any better implementation similar to Python for .. else loop in Java?
It's done like this:
class A {
public static void main(String[] args) {
int n = 13;
found: {
for (int x : new int[]{2,3,4,5,6,7,8,9,10,11,12})
if (n % x == 0) {
System.out.println("" + n + " equals " + x + "*" + (n/x));
break found;
}
System.out.println("" + n + " is a prime number");
}
}
}
$ javac A.java && java A
13 is a prime number
When I need to do something like this, if no extra information is needed, I typically try to break it out into a separate method - which can then return true/false or alternatively either the value found, or null if it's not found. It doesn't always work - it's very context-specific - but it's something worth trying.
Then you can just write:
for (...) {
if (...) {
return separateMethod();
}
}
return null; // Or false, or whatever
No. That's the simplest. It's not that complicated, it's just syntax.
Since java8 there is a way to write this with "nearly no" code:
if(IntStream.range(2, n).noneMatch(x -> n % x == 0)) {
System.out.println(n + " is a prime number");
}
BUT: this would be less efficient than the classical looping-with-break-and-flag method.
No, there is no mechanism like this in Java

Categories