This discussion is archived
10 Replies Latest reply: Oct 11, 2012 5:13 PM by 967605 RSS

(Error in documentation?) Math operator precedence problem

967605 Newbie
Currently Being Moderated
Hello,

I apologize in advance, while I do know programming (I'm a PHP and Perl programmer) I'm fairly new to Java so this may well be a silly question, but that's why I am here. I hope you'll show me where my error is so I can finally set this to rest before it drives me mad :)
(Also, I hope I'm posting this in the right forum?)

So, I am taking a Java class, and the question in the homework related to operand precendence. When dealing with multiplication, division and addition, things were fine, the documentation is clear and it also makes sense math-wise (multiplication comes before addition, etc etc).

However, we got this exercise to solve:

If u=2, v=3, w=5, x=7 and y=11, find the value assuming int variables:

u++ / v+u++ *w


Now, according to the operator precedence table (http://docs.oracle.com/javase/tutorial/java/nutsandbolts/operators.html) the unary operator u++ comes first, before multiplication, division and addition.

This would mean I could rewrite the exercise as:

((u+1)/v) + ((u+1)*w) = (3/3) + (4*5) = 1+20 = 21

However, if I run this in Java, the result I get is 15.


I tried breaking up the result for the two values in the Java code, so I could see where the problem is with my calculation.

For
System.out.println(u++ /v);
I get 0

For
System.out.println("u++ *w");
I get 15

My professor suggested I attempt to change the values from int to float, so I can see if the division came out to be something illogical. I did so, and now I get:

For
System.out.println(u++ /v);
I get 0.66667

For
System.out.println("u++ *w");
I get 15.0000

Which means that for the first operation (the division) the division happens on 2/3 (which is 0.6667) and only afterwards the u value is increased. That is, the u++ operation is done after the division, not before. The same happens with the multiplication; when that is carried out, the value of u is now 3 (after it was raised by one in the previous operation) and the first to be carried out is the multiplication (3*5=15) and only then the u++.

That is entirely against the documentation.


This is the script I wrote to test the issue:

public class MathTest {
     public static void main (String [] args) {
          float u=2, v=3, w=5, x=7, y=11;
          System.out.println("Initial value for 'u': " + u);
          float tmp1 = u++ /v;
          System.out.println("u++ /v = " + tmp1);
          System.out.println("First ++ value for 'u': " + u);
          float tmp2 = u++ *w;
          System.out.println("u++ *w= " + tmp2);
          System.out.println("Second ++ value for 'u': " + u);
          System.out.println(tmp1+tmp2);
     }
}


The output:

Initial value for 'u': 2.0
u++ /v = 1.0
First ++ value for 'u': 3.0
u++ *w= 20.0
Second ++ value for 'u': 4.0
21.0

Clearly, the ++ operation is done after the division and after the multiplication.

Am I missing something here? Is the documentation wrong, or have I missed something obvious? This is driving me crazy!

Thanks in advance,

Mori
  • 1. Re: (Error in documentation?) Math operator precedence problem
    rp0428 Guru
    Currently Being Moderated
    >
    Now, according to the operator precedence table (http://docs.oracle.com/javase/tutorial/java/nutsandbolts/operators.html) the unary operator u++ comes first, before multiplication, division and addition.
    >
    You need to use the Java Language Specification if you want to get the facts about operators such as the prefix and postfix.

    15.14. Postfix Expressions
    http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.14

    As per the Java Language Spec section 15.14.2
    >
    The value of the postfix increment expression is the value of the variable before the new value is stored.
    >
    So what is the value of u before the new value is stored? It is 2 - so that is the value used in the expression.
    >
    Which means that for the first operation (the division) the division happens on 2/3 (which is 0.6667) and only afterwards the u value is increased. That is, the u++ operation is done after the division, not before. The same happens with the multiplication; when that is carried out, the value of u is now 3 (after it was raised by one in the previous operation) and the first to be carried out is the multiplication (3*5=15) and only then the u++.
    >
    Exactly - you got it!
    >
    That is entirely against the documentation.
    >
    WRONG! that is entirely what the documentation (my documentation, not yours) says. The value is incremented AFTER the operation that uses it.
  • 2. Re: (Error in documentation?) Math operator precedence problem
    967605 Newbie
    Currently Being Moderated
    Thanks for the reply.

    For the record, I'm not trying to claim there's an error, I'm asking whether or not there's an error.. and I am asking to get an answer, not to troll, so thanks for the reply, I see what you mean.

    So, just to clarify (more for my own sanity right now, I'm trying to understand this) -- the operator ++ effectively acts after multiplication and division. Is that right?

    I don't mean to be an annoying girl here, but my course book says otherwise, and so did the documentation I found online (hey, to my defense, I tried to find the oracle one, not some random link... but I do see your point about it, and thank you for the link you shared). So I was getting very frustrated when what the book says is different than what actually happened.


    By the way, for the record, wherever I looked (with the exception of your link) I found that ++ comes first. That might not be right, as you pointed out, but it seems to be quite a huge misconception, then? If you look for "java order of operations" on google, the first 2 pages all say ++ comes first on the precedence list... very confusing to first-timers with Java. I wonder where this misconception comes from, if it is so wrong, and how is it that no one noticed that the actual result when you run it doesn't match what you're "supposed" to do...

    Sorry for blabbering, I'm really trying to get this right.

    Thanks!

    Mori
  • 3. Re: (Error in documentation?) Math operator precedence problem
    EJP Guru
    Currently Being Moderated
    So, just to clarify (more for my own sanity right now, I'm trying to understand this) -- the operator ++ effectively acts after multiplication and division. Is that right?
    No. It acts after the operand is evaluated. So the value for the purposes of the rest of the expression is the unincremented operand. It acts before multiply etc as the precedence table says, but its effect isn't part of the resulting value. It changes the operand to the new value but returns the old value into the expression.
  • 4. Re: (Error in documentation?) Math operator precedence problem
    967605 Newbie
    Currently Being Moderated
    Okay, I went over everything again and I think I see what the problem is. The fact that u++ is evaluated but in the calculation itself the "previously stored" value of u is used is completely confusing. My problem is not with the way this works - I understand that this is the way things work in Java (and other languages). My problem is that the documentation in study books at least is extremely misleading.

    Again, if you want any proof of that, go over the docs from different schools and compsci places about u++, and the study books. Neither one that I found separates u++ from any other algebraic operation. So, when they explain that ++ has a higher precedence, the natural thing to consider is that you "do that first" and then do the rest.

    It's confusing, and obviously, since that's not the case, I think people should spend a bit of a longer time going over this specific case of ++ and -- and at the very least explain the issue of using the stored values and how it works before getting newbies to assume that precedence is just precedence.

    This post should've likely been posted in newbies section, not in the programming section. If anyone can move it there, it may help others.

    Thanks for the reply, rp0428

    Mori
  • 5. Re: (Error in documentation?) Math operator precedence problem
    EJP Guru
    Currently Being Moderated
    I can't answer for other books but the tutorial you cited clearly says "the postfix version (result++) evaluates to the original value".
  • 6. Re: (Error in documentation?) Math operator precedence problem
    rp0428 Guru
    Currently Being Moderated
    >
    The fact that u++ is evaluated but in the calculation itself the "previously stored" value of u is used is completely confusing.
    >
    Yes it can be confusing - and no one is claiming otherwise. Here are some more thread links from other users about the same issue.
    Re: Code Behavior is different in C and Java.
    Re: diffcult to understand expression computaion having operator such as i++
    Operator Precedence for Increment Operator
    >
    So, when they explain that ++ has a higher precedence, the natural thing to consider is that you "do that first" and then do the rest.
    >
    And, as you have discovered, that would be wrong and, to a large degree, is the nut of the issue.

    What you just said illustrates the difference between 'precedence' and 'evaluation order'. Precedence determines which operators are evaluated first. Evaluation order determines the order that the 'operands' of those operators are evaluated. Those are two different, but related, things.

    See Chapter 15 Expressions
    >
    This chapter specifies the meanings of expressions and the rules for their evaluation.
    >
    Sections in the chapter specify the requirements - note the word 'guarantees' in the quoted text - see 15.7.1
    Also read carefully section 15.7.2
    >
    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.
    . . .
    15.7.1. Evaluate Left-Hand Operand First
    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.
    . . .
    15.7.2. Evaluate Operands before Operation
    The Java programming language guarantees that every operand of an operator (except the conditional operators &&, ||, and ? appears to be fully evaluated before any part of the operation itself is performed.
    . . .
    15.7.3. Evaluation Respects Parentheses and Precedence
    The Java programming language respects the order of evaluation indicated explicitly by parentheses and implicitly by operator precedence.
    >
    So when there are multiple operators in an expression 'precedence' determines which is evaluated first. And, the chart in your link shows 'postfix' is at the top of the list.

    But, as the quote from the java language spec shows, the result of 'postfix' is the ORIGINAL value before incrementation. If it makes it easier for then consider that this 'original' value is saved on the stack or a temp variable for use in the calculation for that operand.

    Then the evalution order determines how the calculation proceeds.

    It may help to look at a different, simpler, but still confusing example. What should the value of 'test' be in this example?
    i = 0;
    test = i++; 
    The value of 'test' will be zero. The value of i++ is the 'original' value before incrementing and that 'original' value is assigned to 'test'.

    At the risk of further confusion here are the actual JVM instructions executed for your example. I just used
    javap -c -l Test1
    to disassemble this. I manually added the actual source code so you can try to follow this
            int u = 2;
       4:iconst_2        
       5:istore  5
            int v = 3;
       7:iconst_3        
       8:istore          6
            int w = 5;
      10:iconst_5        
      11:istore          7
            int z;
            z = z = u++ / v + u++ * w;
       13:  iload   5
       15:  iinc    5, 1
       18:  iload   6
       20:  idiv
       21:  iload   5
       23:  iinc    5, 1
       26:  iload   7
       28:  imul
       29:  iadd
       30:  dup
       31:  istore  8
       33:  istore  8
    The Java Virtual Machine Specification has all of the JVM instructions and what they do.
    http://docs.oracle.com/javase/specs/jvms/se7/jvms7.pdf

    Your assignment to z and formula starts with line 13: above
    13: iload 5 - 'Load int from local variable' page 466
    15: iinc 5, 1 - 'Increment local variable by constant' page 465
    18: iload 6 - another load
    20: idiv - do the division page
    21: iload 5 - load variable 5 again
    23: iinc 5, 1 - inc variable 5 again
    26: iload 7 - load variable 7
    28: imul - do the multiply
    29: iadd - do the addition
    30: dup - duplicate the top stack value and put it on the stack
    31: istore 8 - store the duplicated top stack value
    33: istore 8 - store the original top stack value

    Note the description of 'iload'
    >
    The value of the local variable at index
    is pushed onto the operand stack.
    >
    IMPORTANT - now note the description of 'iinc'
    >
    The value const is first sign-extended to an int, and then
    the local variable at index is incremented by that amount.
    >

    The 'iload' loads the ORIGINAL value of the variable and saves it on the stack.
    Then the 'iinc' increments the VARIABLE value - it DOES NOT increment the ORIGINAL value which is now on the stack.

    Now note the description of 'idiv'
    >
    The values are popped
    from the operand stack. The int result is the value of the Java
    programming language expression value1 / value2. The result is
    pushed onto the operand stack.
    >
    The two values on the stack include the ORIGINAL value of the variable - not the incremented value.

    The above three instructions explain the result you are seeing. For postfix the value is loaded onto the stack and then the variable itself (not the loaded original value) is incremented.

    Then you can see what this line does
      21:  iload   5 - load variable 5 again
    It loads the variable again. This IS the incremented value. It was incremented by the 'iinc' on line 15 that I discussed above.

    Sorry to get so detailed but this question seems to come up a lot and maybe now you have enough information and doc links to explore this to any level of detail that you want.
  • 7. Re: (Error in documentation?) Math operator precedence problem
    EJP Guru
    Currently Being Moderated
    The instruction set isn't really relevant. The point is what the language specification says.
  • 8. Re: (Error in documentation?) Math operator precedence problem
    rp0428 Guru
    Currently Being Moderated
    >
    The instruction set isn't really relevant. The point is what the language specification says.
    >
    Well I think it's relevant so we'll have to 'agree to disagree' about that.

    The two documents go hand-in-hand. The instruction sequence used to implement what the language spec says helps show more clearly exactly what is happening and how the spec is actually implemented by the JVM I was using (HotSpot Client 1.6.0_22).

    The code sequence shows clearly how the postfix operator can both use the original value of the variable in an expression and increment it so that the second use of the variable fetches it anew. The sequence also shows the how the precedence and order of operations documented in the spec were actually fulfilled.

    I think seeing how things actually work in practice can help demystify some aspects of Java; especially the postfix operator.
  • 9. Re: (Error in documentation?) Math operator precedence problem
    EJP Guru
    Currently Being Moderated
    The JVM wouldn't even need that instruction to implement the language specification. The question was about an apparent conflict with the precedence tables, and you had already answered it.
  • 10. Re: (Error in documentation?) Math operator precedence problem
    967605 Newbie
    Currently Being Moderated
    This is exactly what I was looking for, thank you very much!

    I was trying to understand why it would say "precedence" when in practical terms, if I was to calculate it by hand, I should do this "after". So now I understand that's not quite the case, and I see why. I'll definitely explore more.

    And I still think that at least in books that are meant for new budding programmers, this issue deserves a much bigger notation than just "precedence table" as if it's just the same as multiplication and division. But that, I guess, should be taken up with the authors or publishers. Oh well.

    Thanks again!

    Mori

Legend

  • Correct Answers - 10 points
  • Helpful Answers - 5 points