Why do Unary Post Operators behave differently in C++ and Java? - java

I ran below program in C++(Dec-c++) :
int k = 5;
k = k++;
cout<<"Value of K :"<<k<<endl;
int l = 5;
l = l++ + l++;
cout<<"Value of L :"<<l<<endl;
int m = 5;
m = m++ + m++ + m++;
cout<<"Value of M :"<<m<<endl;
and got 5,12 and 18 for variables k,l and m.. But same program when I ran in java --
int k = 5;
k = k++;
System.out.println("Value of K :"+k);
int l = 5;
l = l++ + l++;
System.out.println("Value of L :"+l);
int m = 5;
m = m++ + m++ + m++;
System.out.println("Value of M :"+m);
I got 5,11 and 18 for variables k,L and M..
Explain why there is difference in calculations of unary post operators ? I am aware of operator's precedence and priority rules. But every thing fails here. But answer from c++ seems rational according to rules. Confused how java is calculating ?
It's well known C++ and Java are different. Please Suggest how operator-precedence and operator-priority is handled in Java.

The rule for Java is quite simple here. The sub-expressions (each call to the postfix operator) are evaluated left to right, each one being fully evaluated before the next.
int k = 5;
k = k++;
This increments k to 6, but returns its previous value (5) and reassigns that to k. So k is 5.
int l = 5;
l = l++ + l++;
The first l++ increments l to 6, and evaluates to its previous value (5). Then the next l++ is called, which increments l to 7, and evaluates to 6. The 5 and 6 are added together and assigned to l, resulting in 11.
int m = 5;
m = m++ + m++ + m++;
Using the same process as before, we just do it one more time, so this is equivalent to adding 5 + 6 + 7 and assigning the result to m, which becomes 18.
The C++, despite your claim that you understand it, is not so simple. In fact, it is undefined behavior, as thoroughly explained in the answers to this question. There are no rules, and you can see any results whatsoever. Don't do it.

Related

How can I reduce time taken for Cardano Triplet Algorithm?

What is Cardano Triplet ?
If a set of any three positive integers, let's say a, b and c satisfies the condition
cbrt(a + b(sqrt(c)) + cbrt(a - b(sqrt(c)) == 1
Explanation.
if sum of Cubic Root of a + (b * square root of c) and Cubic root of a - (b * square root of c) equals 1 then (a, b, c) is said to be a Cardano triplet.
cbrt represents Cubic Root and sqrt means Square Root.
A integer n will be given, so the numbers a, b and c that we take when added should be lesser than or equal to n.
In short a + b + c <= n.
Constraint : n <= 2^31 -1.
Problem
I've already done something which finds out the correct triplets but when the value of n is greater than 1000 the program runs forever.
public static void cardanoTriplets(long n) {
DecimalFormat decimalFormat = new DecimalFormat("#.###");
long numberOfPairs = 0;
for (long a = 0; a <= n; a++) {
for (long b = 0; b <= n; b++) {
for (long c = 0; c <= (n - a - b); c++) {
if ((a + b + c) == n) {
double val = b * Math.sqrt(c);
double LHS = Double.parseDouble(decimalFormat.format(Math.cbrt(a + val)));
double RHS = Double.parseDouble(decimalFormat.format(Math.cbrt(a - val)));
double addedVal = LHS + RHS;
//System.out.println("RHS and LHS -: ( " + RHS + " , " + LHS + " )");
if (addedVal == 1.0d) {
numberOfPairs++;
//System.out.println(a);
//System.out.println(b);
//System.out.println(c + "\n");
}
}
}
}
}
System.out.println(numberOfPairs);
}
Results
When I pass the value of n as 8, on average the time taken to find the cardano triplet is 31ms and sometimes as low as 16ms. The result was accurate and the result is just one and the triplet is (2, 1, 5).
But when I pass the value of n as 1000, it increases to about 1015ms and the result are not as accurate. It misses out almost 19 triplets. Total number of triplets are 149 for n == 1000.
When the value of n > 1000, let's say 5000, it took 29271ms which is 29 seconds approx and the triplets found are 3364.
Is there any way to reduce time taken to a reasonable amount like less than 5 seconds ?
If so how ?
My Device Specs :
Processor : AMD Ryzen 5 3500U Quad Core
RAM : 8 GB
IDE used : IntelliJ IDEA v2021.2.3 (Community Edition)
Thank you :)
This is a number-theoretical problem; using an imprecise floating point is obviously wrong.
The correct solution requires some math insight. Cardano's name is a great hint.
The expression
cbrt(a + b(sqrt(c)) + cbrt(a - b(sqrt(c))
describes a root of a certain cubic equation. Specifically, the roots of an equation
x^3 + px - q = 0
are
cbrt(q/2 + sqrt((q/2)^2 + (p/3)^3)) + cbrt(q/2) - sqrt(q/2)^2 + (p/3)^3))
Comparing with your problem statement, conclude that a = q/2, and c*b^2 = (q/2)^2 + (p/3)^3
Since a is an integer, q must be even, and since b, c are also integers, p must be divisible by 3. Therefore we are interested in the equations
x^3 + 3ux - 2a = 0
having 1 as a root. That narrows the problem down to searching u, v such that 1 + 3u - 2a = 0. Here u^3 + a^2 = b^2*c. Notice that u must be odd.
All these observations lead to a (pseudo)code:
for u in range(1, n, 2)
a = (1 + 3u)/2
t = u^3 + a^2
find the largest b such that b^2 divides t
c = t / b^2
if a + b + c < n
they are a Cardano triplet
Your first problem, is the loop-in-loop-in-loop what will take 1.000.000.000 rounds for n=1000.
As you know already that n = a + b + c, you can take one loop out. the c-loop
and rewrite as:
for (long a = 0; a <= n; a++) {
for (long b = 0; b <= (n - a); b++) {
long c = n - a - b;
so you go from n * n * n -> n * n
If the equation is n => a + b + c (as in your problem statement), you can use:
for (long a = 0; a <= n; a++) {
for (long b = 0; b <= (n - a); b++) {
for (long c = 0; c <= (n - a - b); c++) {
Second, you are doing a format to a decimal and then convert back to double where as the Math.cbrt gives already a double. I would suggest not doing so.
The problem of "missing 19 triplets" is related to the point above. You only accept 1.0d as the correct answer, there in the previous step you did formatting on the doubles (most likely giving rounding issues). Even if you would take out the formatting, I believe it is better to allow for a bit more rounding error..
something like:
if (0.999 < addedVal && addedVal < 1.001)
However, I have no idea on the math of this equation as there must be a reason why you say there are 149 triplets.. Depending on the rounding for sure you have different answers... I believe there is something like mathemathical proof the triplets are 1.
Last what you can do: I believe the calculation of the Math.cbrt is not that fast. You are repeating this a lot. You can keep track of your calculation by placing the result of the Math,cbrt in a HashSet. The Key is the input and the Value the result of the Math.cbrt.
So first check if you have the Key already in the HashSet, if not calculate the cbrt and place it, if already available us it..

Why operator precedence and associativity for increment and decrement in java not working properly?

Operator precedence of ++ and -- is higher than + and has associativity right to left. So I think output of x should be (++i+4 then 5+4) 9 and output of y should be (i+++5 then 5+5) 10. For both it print 11 as output.
class First {
public static void main(String[] args) {
int i = 5;
int x = ++i + --i;
int y = i++ + i--;
System.out.println("x="+x);
System.out.println("y="+y);
}
}
Let's translate this:
int i = 5;
int x = ++i + --i;
int y = i++ + i--;
System.out.println("x=" + x);
System.out.println("y=" + y);
Into (step by step):
int i = 5;
int x = ++i + --i;
// ^
// (i = i + 1) + --i
// (i = 5 + 1) + --i
// (i = 6) + --i
// ^
// 6 + (i = i - 1)
// 6 + (i = 6 - 1)
// 6 + (i = 5)
// 6 + 5
// x = 11
int y = i++ + i--;
// ^
// (i = 5) + i--
// 5 + i--
// i = i + 1 // post evaluation, after i was evaluated to 5, now i increments its value and it is 6
// 5 + (i = 6)
// 5 + 6
// y = 11
// i = i - 1 // post evaluation, after i was evaluated to 6, now i decrements its value and it is 5
System.out.println("x=" + x); // x=11
System.out.println("y=" + y); // y=11
Section 15.7 of the JLS is clear on this:
The Java programming language guarantees that the operands of operators appear to be evaluated in a specific evaluation order, namely, from left to right.
It is recommended that code not rely crucially on this specification. Code is usually clearer when each expression contains at most one side effect, as its outermost operation, and when code does not depend on exactly which exception arises as a consequence of the left-to-right evaluation of expressions.
Whenever assignment operators and other binary operators are mixed in with increment or decrement operators, evaluating the expression is not intuitive, and one should never write such confusing code.
Even if the increment and decrement unary operators are right-to-left associative, the values of an expression are evaluated left-to-right.
int x = ++i + --i;
Here, ++i increments i to 6 and returns 6, then --i decrements i to 5 and returns 5, and the sum of 6 and 5 is 11.
int y = i++ + i--;
Here, i++ returns 5 and increments i to 6, then i-- returns 6 and decrements i to 5, and the sum of 5 and 6 is 11.
With these expressions, the right-to-left associativity does not figure into the order of operations, because associativity only controls which operations are executed first among operators of the same precedence. You have a + operator of lower precedence between them, so the associativity doesn't matter here.
Associativity dictates how operators with the same precedence are parsed.
For example, the Unary Minus (- ...) and Unary Bitwise NOT (~ ...) operators have the same precedence and have right-to-left associativity. Therefore:
int i = ~-1; // == 0
int j = -~1; // == 2

why for loop not showing compile error when i check condition with "<+"?

while practicing, I have accidentally written for loop as below
for (int i = 1; i <+ 100000; i++) {
System.out.println("Iam lazy thread" + i);
}
loop just worked ignoring the plus sign in the condition.
The Java Language Specification includes an unary + operator (ยง15.15.3) which can be used to explicitly express the sign of a numerical value as explained here.
So the expression
i <+ 100000
is parsed as
i < + 100000
It is not a compiler error because + symbol just denotes the positivity of any number later to it.
As same in the math ,
a = 5 and a = +5 are same. You wrote the + which is not necessary as 100000 is already positive. You see the functional difference when you write i < -100000;
It is same as writing
int k = +10000;
or
int k = -10000
"+" determines that 100000 is a positive number. You can try this one
int i = 0;
System.out.println("i <+ :" + (i <+ 10000));
System.out.println("i <- :" + (i <- 10000));

Why is the result not 1? [duplicate]

This question already has answers here:
What is x after "x = x++"?
(18 answers)
If y = 1 and y = y++, why when I print y is the value 1? [duplicate]
Closed 9 years ago.
int m = 0;
m += m++;
System.out.println(m);
prints to 0
but i thought m will be post incremented and finally be 1.
Would someone please explain.
Note: i know how post increment works (atleast i think i do :P). But what i am trying to figure out is that when i say m + = m++ lets assume it means m = m + m++ which will evaluate m++ after sending the value of m, 0 in this case, and evaluate to m = 0 + 0 then increment the value of m because of the post increment. now if post increment has occured, why is m not 1
m++ returns m then increments it.
Change it to ++m and you'll see 1.
For clarity, this question explains it too: What is x after "x = x++"?
Consider the following rules:
a += b is equivalent to a = a + b. Therefore m += m++ is equivalent to m = m + m++.
You can see that the first occurence of m at the right sight is evaluated before the increment and produces 0
m++ increments m and returns original value of m before the increment.
So, in your case m++ sets m to 1 and returns 0
Assignment happens after evaluation of the right side, whereas post-increment happens during evaluation of the right side.
Now you can see that your expression is evaluated as follows:
Evaluation of the right side produces 0 and sets m to 1
Assignment sets m to value of the right side (0)
The sequence of events is:
The RHS is evaluated (0)
The post increment is done (m++).
The evaluated result is assigned (m=0 again).
i.e. this is equivalent to:
tmp = m;
m++;
m = tmp;
If you did m = ++m, the sequence would be:
The pre increment is done (++m).
The RHS is evaluated (1)
The evaluated result is assigned (m=1).
ANSWER: An assignment evaluates side effects before performing the assignment.
m += m++;
is equivalent to
temp = m + m++; ; m is now 1, but temp is 0
m = temp; ; m is now 0 again
int m = 0
At this point m is 0
m += m++;
Expands to m=m+(m++)
m returns 0
m++ returns the value of m which is 0 and then increments it to 1
transforming m+(m++) into 0+0 (m is 1 a this point)
This is then assigned to m resulting in the final value of m.
Tip: avoid post-increment when you're touching the value otherwise
In your code
m+ =m++; Results -- >> M value + (post incremented m value(m++))
Initially
m value= 0
post incremented(m++) m value = 0 (pre increment(++m) = 1)
Well m++ return the value of m before to increment it, contrary to ++m that increment then return, like:
int m++(int m){
int tmp = m;
m = m+1;
return tmp;
}
int ++m(int m){
m = m+1;
return m;
}
f is your code. g is an expanded version showing why they both print 0.
class Test {
private static void f() {
int x = 0;
x += x++;
System.out.println(x);
}
private static void g() {
int x = 0;
int preInc = x; // preInc = 0
x += 1; // x = 1
x = preInc; // x = 0
System.out.println(x);
}
public static void main(String[] args) {
f();
g();
}
}

Bin To Dec code explaination

T student, my teacher said that the codes are okay.. but she asked me that how come binary input 00101 becomes 5.0 dec.
i really need help. i dont know how to explain how 00101 bin becomes 5.0
i tried many calculations like.
5(chararraylength)-3(index)-1 * math.pow = 4
i cant get the last the number that makes my 4 into 5.o dec.
char[] charArray = binary.toCharArray();
double answer = 0;
for (double index = 0; index < charArray.length; index++){
if (charArray[(int)index] == '1') {
answer = answer + Math.pow(2.0, (charArray.length - index - 1));
You use Math.pow() which operates on doubles, this is therefore normal.
Either print (int) answer or use this instead:
final int size = charArray.length;
char c;
int answer = 0;
for (int index = size; index > 0; index++) {
if (charArray[index] == '1')
answer++;
answer <<= 1;
}
Also note that array indices are ints, so your index variable should be an int.
I'm not sure if I understand your question correctly, but here is the calculation the program makes:
00101 means
0*2^4 + 0*2^3 + 1*2^2 + 0* 2^1 + 1* 2^0
= 0*16 + 0*8 + 1*4 + 0*2 + 1*1 = 5
More details at Wikipedia Binary_number

Categories