Incrementor logic
Asked Answered
D

7

20

I'm trying to get deeper with post and pre incrementors but am a bit stuck with the following expression :

public static void main(String[] args) {
    int i = 0;
    i = i+=(++i + (i+=2 + --i) - ++i);
    // i = 0 + (++i + (i+=2 + --i) - ++i);
    // i = 0 + (1   + (3    +   2) -  1 );
    // i = 0 + (6                  -  1 );
    System.out.println(i); // Prints 0 instead of 5
}

I know I'm missing the logic somewhere but where?

What I've tried :

  • Going from left to right (though I know it is not recommended)
  • Going from the insidest bracket and starting from there.

Thanks for the help

PS : The comments are the details of my calculus

EDIT 1

I tried to change de hard coded value from the expression from 2 to something else and the result always gives 0

Look at this example :

    int i = 0;
    i = i+=(++i + (i+=32500 + --i) - ++i);
    System.out.println(i); // Prints 0

This expression should logically be nowhere near 0 but somehow it does print it.

The same happens when I use a negative :

    int i = 0;
    i = i+=(++i + (i+=(-32650) + --i) - ++i);
    System.out.println(i); // Prints 0

EDIT 2

Now, I changed the value of i to begin with :

    int i = 1;
    i = i+=(++i + (i+=2 + --i) - ++i);
    System.out.println(i); // Prints 2
    
    i = 2;
    i = i+=(++i + (i+=10000 + --i) - ++i);
    System.out.println(i); // Prints 4
    
    i = 3;
    i = i+=(++i + (i+=(-32650) + --i) - ++i);
    System.out.println(i); // Prints 6

It gives the double of i each time, whatever the hard coded value is.

Debose answered 14/10, 2015 at 8:48 Comment(13)
could you eleborate why you think it´s 5 instead of 0Sprint
The comments in the code are my calculsDebose
Ahh didn´t catch thatSprint
well going from left to right won't solve it.. the compilers convert normal expressions to reverse polish notations and evaluates them and then constructs a expression tree and solves the expression.Kriss
so simply going from left to right or insidest won't give you the result program will generateKriss
If you "know it is not recommended" why did you do it anyway? Why not do it the recommended way?Erenow
@Thomas and what is the recommended way? That's the point right here.Debose
@Thomas This is simply curiosity indeed. I want to understand everything I'm learning.Debose
Can anyone confirm the first example actually returns 0? Running the code on 1.6, I got result of 3.Symbology
@JiriTousek this is interesting ! Did you copy paste it?Debose
@Yassin I did. I got even more confusing results when I replaced one or both of the i += with i = i + - replacing one of them (don't remember which) led to result 4, replacing the other didn't change the result.Symbology
Would you mind do a printscreen and post it?Debose
@JiriTousek I compiled with 1.4, then ran with following versions, and all produced 0: 1.4.2_19, 1.5.0_22, 1.6.0_45, 1.7.0_79, 1.8.0_51 on Windows 7, Sun/Oracle JVMs.Trill
T
22

Quoting Java Language Specification, 15.7 Evaluation Order:

The Java programming language guarantees that the operands of operators appear to be evaluated in a specific evaluation order, namely, from left to right.

The left-hand operand of a binary operator appears to be fully evaluated before any part of the right-hand operand is evaluated.

If the operator is a compound-assignment operator (§15.26.2), then evaluation of the left-hand operand includes both remembering the variable that the left-hand operand denotes and fetching and saving that variable's value for use in the implied binary operation.

So, essentially, i += ++i will remember the old value of i on the left side, before evaluating the right side.

Remember, evaluation order of operands and precedence of operators are two different things.

Showing evaluation order, step by step, with saved value in {braces}:

int i = 0;
i    = i    += (++i + (i    += 2 + --i) - ++i); // i = 0
i{0} = i    += (++i + (i    += 2 + --i) - ++i); // i = 0
i{0} = i{0} += (++i + (i    += 2 + --i) - ++i); // i = 0
i{0} = i{0} += (1   + (i    += 2 + --i) - ++i); // i = 1
i{0} = i{0} += (1   + (i{1} += 2 + --i) - ++i); // i = 1
i{0} = i{0} += (1   + (i{1} += 2 + 0  ) - ++i); // i = 0
i{0} = i{0} += (1   + (i{1} += 2      ) - ++i); // i = 0
i{0} = i{0} += (1   + 3                 - ++i); // i = 3
i{0} = i{0} += (4                       - ++i); // i = 3
i{0} = i{0} += (4                       - 4  ); // i = 4
i{0} = i{0} += 0                              ; // i = 4
i{0} = 0                                      ; // i = 0
0                                             ; // i = 0

Followup to edits to question

If we name the initial value I and the constant N:

int i = I;
i = i += (++i + (i += N + --i) - ++i);

Then we can see that the values are:

i{I} = i{I} += ((I+1) + (i{I+1} += N + I) - ((I+1+N+I)+1));
i{I} = i{I} += (I + 1 + (I + 1 + N + I) - (I + 1 + N + I + 1));
i{I} = i{I} += (I + 1 + I + 1 + N + I - I - 1 - N - I - 1);
i{I} = i{I} += I;
i{I} = I + I;
i = 2 * I;
Trill answered 14/10, 2015 at 9:37 Comment(3)
Hi Andreas ! This seems to be an acceptable answer indeed but would you mind (if it is not too much asked) apply the same logic when i = something else and also when the hard coded value is bigger than 2 ? That would be awesome, I tried to do it but came with a wrong answerDebose
@YassinHajaj Just did that. :-)Trill
Thank you very much ! That is great !Debose
G
5

This is the logic taking into account your first edit (with an unknown X):

public static void main(String[] args) {
    int i = 0;
    i = i+=(++i + (i+=X + --i) - ++i);
    // i = 0 += (++i + ((i += (X + --i)) - ++i));
    // i = 0 += (1 + ((i += (X + --i)) - ++i)); // i = 1
    // i = 0 += (1 + ((1 += (X + --i)) - ++i)); // i = 1 and i will then take the result of 1 += (X + --i)
    // i = 0 += (1 + ((1 += (X + 0)) - ++i)); // i = 0 and i will then take the result of 1 += (X + 0)
    // i = 0 += (1 + (X + 1 - ++i)); // i = X + 1
    // i = 0 += (1 + (X + 1 - X - 2)); // i = X + 2
    // i = 0 += (0); // i = X + 2
    // i = 0;
    System.out.println(i); // Prints 0
}

Tricks here:

For your second edit (with an unknown I added):

public static void main(String[] args) {
    int i = I;
    i = i+=(++i + (i+=X + --i) - ++i);
    // i = I += (++i + ((i += (X + --i)) - ++i));
    // i = I += (I+1 + ((i += (X + --i)) - ++i)); // i = I+1
    // i = I += (I+1 + ((I+1 += (X + --i)) - ++i)); // i = I+1 and i will then take the result of I+1 += (X + --i)
    // i = I += (I+1 + ((I+1 += (X + I)) - ++i)); // i = I and i will then take the result of I+1 += (X + I)
    // i = I += (I+1 + (X+2*I+1 - ++i)); // i = X + 2*I + 1
    // i = I += (I+1 + (X+2*I+1 - X-2*I-2)); // i = X + 2*I + 2
    // i = I += (I); // i = X + 2*I + 2
    // i = 2 * I;
    System.out.println(i); // Prints 2 * I
}
Goode answered 14/10, 2015 at 9:16 Comment(3)
following that logic, could you eleborate why i = i+= (++i + (i+=2)) == i = i+= (++i + (i+=2 + --i)); = 4Sprint
I'm editing the question because I came to something else really weird !Debose
Hey @Tunaki, could you check the edit I made to the post. This logic does not apply anymoreDebose
E
4

I suggest the following: format the code differently, so that there's only 1 statement per line, e.g.

@Test
public void test() {
    int i = 0;
    i = 
    i+=
    (
    ++i 
    + 
    (
    i+=
    2 
    + 
    --i
    ) 
    -
    ++i
    );
    System.out.println(i); // Prints 0 instead of 5
}

Then run it under the debugger and press F5 ("Step into") always. This will help you to understand in which order items get evaluated:

  1. int i=0;
  2. i=: ... (needs to wait for result of calculation A)
  3. i+= ... (needs to wait B)
  4. ++i: i=1
  5. i+= ... (needs to wait C)
  6. 2+
  7. --i: i=0
  8. ...: i=3 (result for wait C)
  9. -
  10. ++i: i=4 and operand of - is also 4
  11. ...: i=0 (result for wait B)
  12. ...: i=0 (result for wait A)

Line 10 will always make the result of line 3 0, so the initial value of i will never be changed by the whole operation.

Erenow answered 14/10, 2015 at 9:32 Comment(0)
P
1

Ok, let's break down every thing:

int i = 0; // i = 0, no big deal

Then starting into the most inner parenthesis:

(i+=2 + --i)
  • it first decrement i and use the result (-1)
  • then add 2 (-1+2=1)
  • and add the result to i (which is 0 at the start of the operation) (0+1=1=i)

At the end, the first decrement is ignored by the reassignation.

Next parenthesis:

i+= (++i + previous_result - ++i)
  • it increase the i ( with ++i) at two points
  • then the operation becomes (i+1) + previous_result - (i+2) (notice how the increment are not simultaneous) that gives 2 + 1 - 3 = 0.
  • the result of the operation is added to the initial i (0)

Again the increment will get discard by the reassignation.

finally:

i = previous_result

Which gives 0 :)

Pubescent answered 14/10, 2015 at 9:13 Comment(1)
I'm editing the question because I came to something else really weird !Debose
I
1

Because of the highest precedence (...) will be evaluated first then ++ & -- and then remaining operators. Your expression is like

i = i += ( (++i) + (i+=2 + (--i)) - (++i) );

//i = i = i + ( (++i) + (i+=2 + (--i)) - (++i) );
//i = i = 0 + ( (++i) + (i+=2 + (--i)) - (++i) );
//i = i = 0 + ( (1) + (i+=2 + (--i)) - (++i) );
//i = i = 0 + ( (1) + (i+=2 + (0)) - (++i) );
//i = i = 0 + ( (1) + (2 + (0)) - (++i) );
//i = i = 0 + ( (1) + (2) - (++i) );
//i = i = 0 + ( (1) + (2) - (3) );
//i = i = 0 + ( 3 - 3 );
//i = i = 0 + ( 0 );
//i = 0

Please fully parenthesize your expression. You will understand evaluation order of expression.

For your EDIT 1

i = i+=( (++i) + (i+=32500 + (--i) ) - (++i) ); 

// 0 + ( (++i) + (i+=32500 + (--i) ) - (++i) ); // i = 0
// 0 + ( (1) + (i+=32500 + (--i) ) - (++i) );  // i = 1
// 0 + ( (1) + (i+=32500 + (0) ) - (++i) ); // i = 0
// 0 + ( (1) + (32500 + (0) ) - (++i) );  // i = 32500
// 0 + ( (1) + (32500) - (++i) ); // i = 32500
// 0 + ( (1) + (32500) - (32501) ); // i = 32501
// 0 + ( 32501 - 32501 ); // i = 32501
// 0 // i = 0
Immeasurable answered 14/10, 2015 at 9:39 Comment(0)
H
1

I traced the value of i and here are the results:

i = i+=(++i + (i+=2 + --i) - ++i);
initialization: i = 0;
++i: i = 1;(1st one) and store this value
(i+=2 + --i): In it
 --i: i = 0;(i was changed by the previous ++i)
 i += 2 + 0: i = 2;(value of the inner (i+=2 + --i), store it)
++i: i = 3;
1 + 2 -3: i = 0;
i += 0: i = 0;

The value of the 2nd i from the left is not zero, it is the value of i after all the operations to the right are finished.

Hushhush answered 14/10, 2015 at 9:49 Comment(0)
V
0

Paranthesis takes the precedence. order would be from inner most to outermost

(i+=2 + --i) =>i=i+=2==(2) --2 =0 
(++i - ++i)  =>1-1=0 
i=i+ =0+0 =0

Each expression evaluates to 0

Vandal answered 14/10, 2015 at 9:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.