...

View Full Version : Any differences in loop increment method?



jmrker
09-02-2011, 05:48 AM
The following code results in the exact same output.
Is there an advantage to using i++ over ++i (or visa-versa) in the loop? :confused:



<script type="text/javascript">
var tarr1 = []; for (var i=0; i<10; i++) { tarr1.push(i); }
var tarr2 = []; for (var i=0; i<10; ++i) { tarr2.push(i); }
alert(tarr1.join(',')+'\n'+tarr2.join(','));
</script>


Similar question for the increment method in the following:


<script type="text/javascript">
var tarr1 = []; var i=0; do { tarr1.push(i); i++; } while (i<10);
var tarr2 = []; var j=0; do { tarr2.push(j); ++j; } while (j<10);
alert(tarr1.join(',')+'\n'+tarr2.join(','));
</script>

Old Pedant
09-02-2011, 06:58 AM
No.

And with modern C/C++/Java compilers it makes very very little difference (at most one machine instruction) in *any* circumstance.

More than likely, the same is true of JavaScript, but I can't swear to it.

The ONLY time it makes a difference is when you *use* the result of the increment (or decrement) in an expression.

Such as:


<script type="text/javascript">
var tarr1 = []; var i=0; do { tarr1.push(i++); } while (i<10);
var tarr2 = []; var j=-1; do { tarr2.push(++j); } while (j<9);
alert(tarr1.join(',')+'\n'+tarr2.join(','));
</script>

It is *conceivable* that the second loop will execute faster.

Here's why: When you use post-increment, the language specification says "the value of the expression is the value *before* the increment, so the increment must not be visible to the consumer of the expression". (Or words to that effect, depending on what spec your read.)

Whereas with pre-increment, the value is incremented and *then* used in the expression.

The machine code for PRE-increment is quite simple:


loadregister A from i
increment A
storeregister A into i
call push( ) [the register is the argument to the push function]


But with POST-increment, at the machine code level, that means the compiler needs to generate something like this:


loadregiste A from i
call push() function
loadregister A from i
increment A
storeregister A into i

One extra machine instruction, to reload the register so it can be incremented and stored.

And back when I was generating code for a C compiler for Z-80 processors (an 8 bit CPU! The biggest register held only16 bits), that's pretty much what we had to do.
But with today's CPUs, their instruction set is so rich that they *probably* can generate code such as this:


/* implemient push[i++] */
load i in A
call push() function
incrementMemoryLocation i

versus


/* implemient push[++i] */
incrementMemoryLocation i
load i in A
call push() function

So in actuality there may very well be zero difference in performance. But even in the worst case, it's no more than 1 or possibly 2 machine instructions different.

**********

NOW... all that was for a *pure* compiler. One that compiles your source code down into machine language. So far as I know, no current JavaScript engine does that. Instead, they compile the JavaScript source into an intermediate tokenized form (in fact, that's what compliant JAVA compilers do!) and then a run-time engine "interprets" the intermediate tokens when the code runs. In consequence, JavaScript is much much slower than true compiled languages. And I can't predict what the effect of pre vs. post increment is for the different JS engines. Were I *guessing*, I'd guess that it is more like that old C compiler of ours. One or two "tokens" of difference and so a few extra machine cycles for post-increment.

NOTICE THAT NONE OF THIS APPLIES to any of the code that you showed!! Because none of your code "consumed" the value of the incremented variable as part of some larger expression. So in all cases, all the compiler has to do is generate a single increment. And even a not-too-smart compiler will recognize that the two operations are identical in semantics in this case.

[If you are curious: I said that JAVA compilers create an internal tokenized form--the so-called "byte code"--as do all of the MS ".NET" languages. The difference in those languages is that they then have an additional compilation stage--usually called a Just In Time compiler or "JIT" (pronounced just as spelled, with a short "i")--that then renders the byte code into machine code. By writing compilers this way, all the HARD work of smart code generation is the same, done when creating the byte code. And you only have to write a specific "JIT" for each separate CPU architecture.]

jmrker
09-02-2011, 03:48 PM
Thanks for the information.

I had noticed you often used the pre-fixed version of the loop
and I was accustomed to using the other.

I was interested as to why when I saw no difference in the actual effect.

Old Pedant
09-02-2011, 09:46 PM
Habit.

Plus because of my compiler experience I learned to use pre unless post is really needed.

The need to do so today is so much less than it was in 1979 (yeah, that's when I wrote the code generator for that C compiler for an 8-bit machine) that even "habit" isn't a good reason. But that's all I have.



EZ Archive Ads Plugin for vBulletin Copyright 2006 Computer Help Forum