No, but yes, but maybe, but maybe the other way, but no.
As people have already pointed out, (assuming a language where addition is left-associative, such as C, C++, C# or Java) the expression ((1 + 2) + 3)
is exactly equivalent to 1 + 2 + 3
. They're different ways of writing something in the source code, that would have zero effect on the resulting machine code or byte code.
Either way the result is going to be an instruction to e.g. add two registers and then add a third, or take two values from a stack, add it, push it back, then take it and another and add them, or add three registers in a single operation, or some other way to sum three numbers depending on what is most sensible at the next level (the machine code or byte code). In the case of byte code, that in turn will likely undergo a similar re-structuring in that e.g. the IL equivalent of this (which would be a series of loads to a stack, and popping pairs to add and then push back the result) would not result in a direct copy of that logic at the machine code level, but something more sensible for the machine in question.
But there is something more to your question.
In the case of any sane C, C++, Java, or C# compiler, I would expect the result of both of the statements you give to have the exact same results as:
int a = 6;
Why should the resultant code waste time doing math on literals? No changes to the state of the program will stop the result of 1 + 2 + 3
being 6
, so that's what should go in the code being executed. Indeed, maybe not even that (depending on what you do with that 6, maybe we can throw the whole thing away; and even C# with it's philosophy of "don't optimise heavily, since the jitter will optimise this anyway" will either produce the equivalent of int a = 6
or just throw the whole thing away as unnecessary).
This though leads us to a possible extension of your question though. Consider the following:
int a = (b - 2) / 2;
/* or */
int a = (b / 2)--;
and
int c;
if(d < 100)
c = 0;
else
c = d * 31;
/* or */
int c = d < 100 ? 0 : d * 32 - d
/* or */
int c = d < 100 && d * 32 - d;
/* or */
int c = (d < 100) * (d * 32 - d);
(Note, this last two examples are not valid C#, while everything else here is, and they are valid in C, C++ and Java.)
Here again we've exactly equivalent code in terms of output. As they aren't constant expressions, they won't be calculated at compile time. It's possible that one form is faster than another. Which is faster? That would depend on the processor and perhaps on some rather arbitrary differences in state (particularly since if one is faster, it's not likely to be a lot faster).
And they aren't entirely unrelated to your question, as they are mostly about differences in the order in which something is conceptually done.
In each of them, there's a reason to suspect that one may be faster than the other. Single decrements may have a specialised instruction, so (b / 2)--
could indeed be faster than (b - 2) / 2
. d * 32
could perhaps be produced faster by turning it into d << 5
so making d * 32 - d
faster than d * 31
. The differences between the last two are particularly interesting; one allows some processing to be skipped in some cases, but the other avoids the possibility of branch mis-prediction.
So, this leaves us with two questions: 1. Is one actually faster than the other? 2. Will a compiler convert the slower into the faster?
And the answer is 1. It depends. 2. Maybe.
Or to expand, it depends because it depends on the processor in question. Certainly there have existed processors where the naïve machine-code equivalent of one would be faster than the naïve machine-code equivalent of the other. Over the course of the history of electronic computing, there hasn't been one that was always the faster, either (the branch mis-prediction element in particular wasn't relevant to many when non-pipelined CPUs were more common).
And maybe, because there are a bunch of different optimisations that compilers (and jitters, and script-engines) will do, and while some may be mandated in certain cases, we'll generally be able to find some pieces of logically equivalent code that even the most naïve compiler has exactly the same results and some pieces of logically equivalent code where even the most sophisticated produces faster code for one than for the other (even if we have to write something totally pathological just to prove our point).
It might seems like a very tiny optimization concern,
No. Even with more complicated differences than those I give here, it seems like an absolutely minute concern that has nothing to do with optimisation. If anything, it's a matter of pessimisation since you suspect the harder to read ((1 + 2) + 3
could be slower than the easier to read 1 + 2 + 3
.
but choosing C++ over C#/Java/... is all about optimizations (IMHO).
If that's really what choosing C++ over C# or Java was "all about" I'd say people should burn their copy of Stroustrup and ISO/IEC 14882 and free up the space of their C++ compiler to leave room for some more MP3s or something.
These languages have different advantages over each other.
One of them is that C++ is still generally faster and lighter on memory use. Yeah, there are examples where C# and/or Java are faster and/or have better application-lifetime use of memory, and these are becoming more common as the technologies involved improve, but we can still expect the average program written in C++ to be a smaller executable that does its job faster and using less memory than the equivalent in either of those two languages.
This isn't optimisation.
Optimisation is sometimes used to mean "making things go faster". It's understandable, because often when we really are talking about "optimisation" we are indeed talking about making things go faster, and so one has become a shorthand for the other and I'll admit I misuse the word that way myself.
The correct word for "making things go faster" is not optimisation. The correct word here is improvement. If you make a change to a program and the sole meaningful difference is that it is now faster, it isn't optimised in any way, it's just better.
Optimisation is when we make an improvement in regards to a particular aspect and/or particular case. Common examples are:
- It's now faster for one use case, but slower for another.
- It's now faster, but uses more memory.
- It's now lighter on memory, but slower.
- It's now faster, but harder to maintain.
- It's now easier to maintain, but slower.
Such cases would be justified if, e.g.:
- The faster use case is more common or more severely hampered to begin with.
- The program was unacceptably slow, and we've lots of RAM free.
- The program was grinding to a halt because it used so much RAM it spent more time swapping than executing its super-fast processing.
- The program was unacceptably slow, and the harder to understand code is well-documented and relatively stable.
- The program is still acceptably fast, and the more understandable code-base is cheaper to maintain and allows for other improvements to be more readily made.
But, such cases would also not be justified in other scenarios: The code hasn't been made better by an absolute infallible measure of quality, it's been made better in a particular regard that makes it more suitable for a particular use; optimised.
And choice of language does have an effect here, because speed, memory use, and readability can all be affected by it, but so can compatibility with other systems, availability of libraries, availability of runtimes, maturity of those runtimes on a given operating system (for my sins I somehow ended up having Linux and Android as my favourite OSs and C# as my favourite language, and while Mono is great, but I still come up against this one quite a bit).
Saying "choosing C++ over C#/Java/... is all about optimizations" only makes sense if you think C++ really sucks, because optimisation is about "better despite..." not "better". If you think C++ is better despite itself, then the last thing you need is to worry about such minute possible micro-opts. Indeed, you're probably better off abandoning it at all; happy hackers are a quality to optimise for too!
If however, you're inclined to say "I love C++, and one of the things I love about it is squeezing out extra cycles", then that's a different matter. It's still a case that micro-opts are only worth it if they can be a reflexive habit (that is, the way you tend to code naturally will be the faster more often than it is the slower). Otherwise they're not even premature optimisation, they're premature pessimisation that just make things worse.