Post your code optimizations

DemoCoder said:
Isn't the order of evaluation of floating point defined tho? Since FP is neither associative nor commutative, it would seem pretty important.
The order of non-side-effect subexpressions is perfectly defined in C. The problem comes from subexpressions that have side-effects. Since i++ and ++i aren't defined for floats, that leaves you with indirection and assignment subexpressions (which aren't all that common).
 
Bob said:
The order of non-side-effect subexpressions is perfectly defined in C.
"The New C Standard"
937 Except as specified later (for the function-call (), &&, ||, ?:, and comma operators), the order of evaluation of subexpressions and the order in which side effects take place are both unspecified.
@DemoCoder:
959 A floating expression may be contracted, that is, evaluated as though it were an atomic operation, thereby omitting rounding errors implied by the source code and the expression evaluation method.
...
966 As contractions potentially undermine predictability, and can even decrease accuracy for containing expressions, their use needs to be well-defined and clearly documented.
 
DemoCoder said:
IIRC, Isn't the order of evaluation of floating point defined tho? Since FP is neither associative nor commutative, it would seem pretty important.
I think the problem is only for expressions with side-effects which, IMHO, are the devil's own spawn.

EDIT: I see I stand corrected. Looks like you should use brackets if order is important!!!
 
Last edited by a moderator:
DemoCoder said:
IIRC, Isn't the order of evaluation of floating point defined tho? Since FP is neither associative nor commutative, it would seem pretty important.
See the expression as a tree. It's defined where the branches are located, but it's not defined in which order they are evaluated. (Other than, of course, that the subexpressions into an operator must be evaluated before that operator is. :))

(A) + (B) + (C) where A, B and C are subexpressions must be calculated as
((A) + (B)) + (C), but A, B and C can be calculated in any order.

(The compiler may move "where the branches are" for associative operators like integer add, but that's a sidepoint.)

[Added]
And just before I posted this, I saw Mate's post. I didn't know about those contractions. But it seems reasonable for hardware that have a dot product instruction. I *think* that it is like I said for "The Old C Standard", but since I didn't know about it in C99, I might have made the same error in the older one too.

One thing is for sure though, evaluation order of A, B, and C is undefined.
 
Xmas said:
That sucks donkey balls!

Sorry for my language... I was always convinced that evaluation order was well defined. The only exception I knew was evaluation of function arguments (which is slightly understandable because arguments are equivalent and separate expressions). But I was taught that everything else had a strict evalutation order. Even this reference fully defines precedence and associativity.

It sucks though (sorry again). What do we have high level languages for if it's more dangerous than assembly in some aspects? The argument of performance for having undefined evaluation order is nonsense. For well-defined expressions it doesn't matter, and for expressions that are currently undefined I much rather would have them well-defined than fast. Besides, it's easy for optimizing compilers to check side-effects and see whether evaluation order can be changed to improve performance. For example a + b + c + d (all integers) should have left to right associativity ((a + b) + c) + d but it's faster to do (a + b) + (c + d) if there are enough registers, without any problem.

Anyway, I'm utterly dissapointed about this. And I still don't fully understand it, much less the reasons behind it. Is evaluation order well defined for a more modern language, say, C#? Are there any plans to correct C++ in the near future?

Thanks...
 
Nick said:
...
Anyway, I'm utterly dissapointed about this. And I still don't fully understand it, much less the reasons behind it. Is evaluation order well defined for a more modern language, say, C#? Are there any plans to correct C++ in the near future?

Thanks...
Im surprised (rather shocked) about this too, but I think C++ has to be implicitely defined order of evalutation, since someone could be stupid enough to overload +. AFAIK all operators get converted to their functional counterpart before evaluating.

stdout << a << b << c;
x = a + b + c + d;

gets converted to

((stdout.<<( a )).<<(b)).<<(c);
x = ((a.+( b )).+(c)).+(d);

defining automatically a left-to-right evaluation order. I`m gonna have a look in my Stroustrup too.
 
Nick said:
Even this reference fully defines precedence and associativity.
And it's perfectly sound. Precedence and associativity definitely have something to do with run-time evaluation order, but not everything. See Basic's post above.
The basis of the misconception (IMO) is that people usually talk about "evaluation order" when explaining precedence and associativity, and they forget to add "parse-time evaluation order". I prefer thinking of precedence and associativity as the "stickyness" (grouping) of operators.
 
DiGuru said:
I always use brackets, just to be sure.
Sure, but it's not unreasonable to write your expressions in a compact manner, test it on one compiler, and expect it to give the same result on other compilers, is it? I mean, I too use brackets fairly much, but that's because I'm not always 100% sure about operator precedence (even though it's well-defined - I just don't always take the time to look it up) and to make the code easier to read. But in the few situations where I don't add extra brackets I do expect equal results across compilers.

That being said, is (i++) + (i++) well defined? I'm still totally confused now... part of my world fell apart...
 
Nick said:
Sorry for my language... I was always convinced that evaluation order was well defined. The only exception I knew was evaluation of function arguments (which is slightly understandable because arguments are equivalent and separate expressions).
But operators are no different than function calls.
Code:
a = b + c;
a = operator+(b, c);

j = i++ + i;
j = operator+(operator++(i, 0), i);
See the problem? There is no guarantee that "operator++(i, 0)" (the additional int argument distinguishes postincrement from preincrement) is evaluated before "i" (where "evaluation" means loading into a register).


Anyway, I'm utterly dissapointed about this. And I still don't fully understand it, much less the reasons behind it. Is evaluation order well defined for a more modern language, say, C#? Are there any plans to correct C++ in the near future?
Both Java and C# guarantee left-to-right evaluation order.
 
Notice that precedence and associativity tells how the expression tree looks (except for the "contractions" that Mate posted about).
But they do not tell in which order the branches in the tree are evaluated.
The link you posted is perfectly true, Nick. But it only talks about precedence and associativity.

Parenthesis are used to overide the operators precedence and associativity, but do not change evaluation order. (Other than the obvious one that subexpressions must be evaluated before the operator who works on them.)

So no amount of parenthesises will help that expressions with side effects are undefined if other parts of the same expression depends on that side effect.

Nick said:
That being said, is (i++) + (i++) well defined?
No.
I assume that you thought that if i starts as 2, then that expression could be 2+3 or 3+2, both equal to 5.
But IIRC it is a bit worse than that. The increment must be done before the ending semicolon of the statement, so a compiler has the right to do this.
Code:
// Real code:
j = (i++) + (i++);

// Calculate as:
j = i + i; // Or 2*i
i += 2;
Same thing with pre-increment. It must be done somewhere between the end of last statement (semicolon or equivalent), and when the value is used.


But this undefined evaluation order is usually no big problem, as far as you know it.

The coding rule is simply that if you do an i++ or ++i in an expression, never reference i at any other place in the same expression. If you just stick to that, everything works as you always thought it did. (Again except for the contractions.)

The only problem is the contractions which could hurt numerically critical code real bad. A good thing that they added a "#pragma fp_contract off".

[Edit]
Btw, I could connect this to the coding style thread by saying that you shouldn't use i++ and other uses of i in the same expression anyway. It's usually not a readable coding style.
 
Last edited by a moderator:
Nick said:
That being said, is (i++) + (i++) well defined? I'm still totally confused now... part of my world fell apart...
How about:

i += (i++)++;

or:

i++ += i++;

?

They should be defined.

It's all about only doing a single action in each separate part of your expression. Just don't use any ambigious constructs.
 
DiGuru said:
How about:

i += (i++)++;

or:

i++ += i++;

?
They should be defined.
These don't cause undefined behavior; they don't compile at all. You're trying to assign to something that isn't an lvalue. The basic idea is that while 'i' is a variable in its own right, the expression 'i++' is not. It is just a value, and as such the ++ operator does not make any sense on it. You might as well try to explain how code like
Code:
int p = (i+2)++ +j;
ought to behave.
 
arjan de lumens said:
You're trying to assign to something that isn't an lvalue. The basic idea is that while 'i' is a variable in its own right, the expression 'i++' is not. It is just a value, and as such the ++ operator does not make any sense on it.
I don't agree, as the ++ operator is supposed to change the actual value of the variable. It's not a computed value, but a lookup that is pre- or postprocessed (postprocessed in this case).

Edit:

i += (i++)++;

should evaluate as:

i += i;
i++;
i++;

and

i++ += i++;

should behave the same.
 
Last edited by a moderator:
Well, I think that (i++)++ would actually be the same as i++, since the ++ outside of the parentheses would be evaluated on a temporary variable (the return value of i++).
 
The post[++/--] operators need and lvalue as argument, and they return a non-lvalue. So expressions like "1++" and "(i++)++" are invalid.
 
Chalnoth said:
Well, I think that (i++)++ would actually be the same as i++, since the ++ outside of the parentheses would be evaluated on a temporary variable (the return value of i++).
I don't think it has a return value, as it shouldn't be a value. The value during execution would be just i, nothing more. And afterwards, i would be incremented. Twice. That's the idea about it, AFAIK.
 
Back
Top