Thread: Operator Precedence?

  1. #1
    and the hat of sweating
    Join Date
    Aug 2007
    Location
    Toronto, ON
    Posts
    3,545

    Operator Precedence?

    I just noticed something a bit strange at the bottom of this page:
    http://www.cppreference.com/operator_precedence.html

    For this code:
    Code:
    float x = 1;
    x = x / ++x;
    It says:
    The value of x is not guaranteed to be consistent across different compilers, because it is not clear whether the computer should evaluate the left or the right side of the division first. Depending on which side is evaluated first, x could take a different value.
    But the ++ pre-increment operator is 2 levels above the / division operator, so I don't see why there would be any confusion about what to do first?
    Is that page incorrect? If not, how can it be true?

  2. #2
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    Yes, but when should the compiler grab the value of x to use on the left side of the division: before anything happens, or just when it is needed? You don't know, and I don't know.

  3. #3
    Registered User
    Join Date
    Oct 2001
    Posts
    2,934
    >because it is not clear whether the computer should evaluate the left or the right side of the division first.
    So is the x on the left side of the division the original x, or the new x? The following suffers from the same ambiguity:
    Code:
    float x = 1;
    x = x / x++;

  4. #4
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by cpjust View Post
    But the ++ pre-increment operator is 2 levels above the / division operator, so I don't see why there would be any confusion about what to do first?
    Is that page incorrect? If not, how can it be true?
    The relative precedence of the operators has nothing to do with it. Precedence only comes into play when there is an ambiguity about which operator should be applied first -- in other words, which expression the operator binds to most tightly. There is no ambiguity here in that regard. The preincrement operator clearly must bind to 'x' and nothing else.

    What is ambiguous is whether the left side or the right side of the division expression will be evaluated first.

  5. #5
    and the hat of sweating
    Join Date
    Aug 2007
    Location
    Toronto, ON
    Posts
    3,545
    Quote Originally Posted by brewbuck View Post
    The relative precedence of the operators has nothing to do with it. Precedence only comes into play when there is an ambiguity about which operator should be applied first -- in other words, which expression the operator binds to most tightly. There is no ambiguity here in that regard. The preincrement operator clearly must bind to 'x' and nothing else.

    What is ambiguous is whether the left side or the right side of the division expression will be evaluated first.
    I thought it would have done it in steps:
    First do ++x
    Then do x / x

    If I was writing a compiler, I'm sure that's how I'd make it work.

    And since ++ happens before /, I don't see the problem.
    x was 0, then it gets incremented to 1, so you have 1 / 1.
    The compiler can't see it as 0 / 0 because ++ has a higher precedence, and it would never see it as 0 / 1 would it?

  6. #6
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by cpjust View Post
    I thought it would have done it in steps:
    First do ++x
    Then do x / x
    What's so special about the right hand side -- why should it get evaluated first?

    If I was writing a compiler, I'm sure that's how I'd make it work.
    The order of evaluation of subexpressions was deliberately left unspecified so that compilers could actually optimize stuff.

    And since ++ happens before /, I don't see the problem.
    Why do you think the ++ happens before / ? The order of evaluation is unspecified.

    The compiler can't see it as 0 / 0 because ++ has a higher precedence, and it would never see it as 0 / 1 would it?
    Again, precedence has absolutely nothing to do with this. If the precedence of / and ++ were reversed the exact same ambiguity would remain.

  7. #7
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    The compiler can't see it as 0 / 0 because ++ has a higher precedence, and it would never see it as 0 / 1 would it?
    Actually, I know a few compilers that will see it as "0/0" with optimizations turned on, but it's unusual for a compiler to try that. Anyway, it depends on how the compiler was designed.

    The compiler might see this source as:

    Code:
    ++x;
    x /= x;
    or

    Code:
    y = x;
    ++x;
    y /= x;
    Soma
    Last edited by phantomotap; 05-02-2008 at 03:59 PM.

  8. #8
    and the hat of sweating
    Join Date
    Aug 2007
    Location
    Toronto, ON
    Posts
    3,545
    Quote Originally Posted by brewbuck View Post
    The order of evaluation of subexpressions was deliberately left unspecified so that compilers could actually optimize stuff.
    OK, maybe I'm not understanding the point of the Order of Evaluation correctly, but I thought it was the same as the order of operations that they teach us in math class.
    i.e. 2*4+5/2-6*9 = (2*4) + (5/2) - (6*9) instead of 2 * (4+5) / (2-6) * 9 or anything in between.

    Quote Originally Posted by brewbuck View Post
    Why do you think the ++ happens before / ? The order of evaluation is unspecified.
    A higher precedence means that operation will be evaluated before ones with a lower precedence, right? So how can it be unspecified if ++ is 2 levels higher than /

  9. #9
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    This has nothing to do with order of operations[*] and everything to do with the fact that you have the same letter in two different places. If it was y/++x, everything would be completely spiffy. But you have x/++x. Does the first x refer to the x we had when we started, or the x we get after incrementing? Yes, ++ happens before /, but that has nothing to do with the problem -- why should what appears on the right side of the division sign affect what appears on the left side of the division sign? The view of the standard is that there is no legitimate use of the expression "x/++x" and consequently the compiler can do whatever it wants.
    Last edited by tabstop; 05-02-2008 at 04:32 PM. Reason: see two posts down

  10. #10
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by cpjust View Post
    OK, maybe I'm not understanding the point of the Order of Evaluation correctly, but I thought it was the same as the order of operations that they teach us in math class.
    i.e. 2*4+5/2-6*9 = (2*4) + (5/2) - (6*9) instead of 2 * (4+5) / (2-6) * 9 or anything in between.
    That's not the question. The question is, do you evaluate the (4+5) first, or the (6*9)? Clearly it doesn't matter, since the result does not depend on that.

    Maybe a very simple example will help.

    Code:
    foo() + bar();
    Will foo() get called first, or bar()? It is unspecified. There is no issue of precedence, since only a single operator is involved here.

    A higher precedence means that operation will be evaluated before ones with a lower precedence, right? So how can it be unspecified if ++ is 2 levels higher than /
    Precedence has nothing to do with order of evaluation. It has to do with how the operators bind to operands.

  11. #11
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by tabstop View Post
    This has nothing to do with order of evaluation and everything to do with the fact that you have the same letter in two different places.
    No, it is the reuse of the same variable which causes the order of evaluation to start making a difference, whereas in most other situations it would not matter.

  12. #12
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    Quote Originally Posted by brewbuck View Post
    No, it is the reuse of the same variable which causes the order of evaluation to start making a difference, whereas in most other situations it would not matter.
    Yes, that's right. I meant order of operations and will edit to reflect that.

  13. #13
    Just Lurking Dave_Sinkula's Avatar
    Join Date
    Oct 2002
    Posts
    5,005
    7. It is easier to write an incorrect program than understand a correct one.
    40. There are two ways to write error-free programs; only the third one works.*

  14. #14
    Algorithm Dissector iMalc's Avatar
    Join Date
    Dec 2005
    Location
    New Zealand
    Posts
    6,318
    Perhaps this will explain it better. Take a look at the following line:
    Code:
    result = a() * b() + c() * d();
    Precedence rules tell us that the parse tree looks like this:
    Code:
             +
          /     \
        *         *
      /   \     /   \
    a()   b() c()   d()
    instead of for example this:
    Code:
        *
      /   \
    a()     +
          /   \
        b()    *
             /   \
           c()   d()
    However you don't know what order a(), b(), c() and d() will be called. That's evaluation, not precedence.
    It could call c() then d(), then do the second *, then call a, then b, then do the first *, then do the +. If the functions a, b, c, and d all make certain modifications to a global variable and then return the current value of that global variable for example, then different evaluation orders would produce different results.

    However, no compiler would be allowed to generate the second parse tree I showed as it has incorrect precedence rules applied to it. Only using brackets could allow such a parse tree to result.
    My homepage
    Advice: Take only as directed - If symptoms persist, please see your debugger

    Linus Torvalds: "But it clearly is the only right way. The fact that everybody else does it some other way only means that they are wrong"

  15. #15
    Registered User
    Join Date
    Oct 2001
    Posts
    2,934
    >If it was y/++x, everything would be completely spiffy.
    That would be undefined as well if there's an x left of the assignment operator.

Popular pages Recent additions subscribe to a feed