views:

980

answers:

7

I've heard this quite a few times. Are JavaScript loops really faster when counting backward? If so, why? I've seen a few test suite examples showing that reversed loops are quicker, but I cant find any explanation as to why!

I'm assuming it's because the loop no longer has to evaluate a property each time it checks to see if it's finished and it just checks against the final numeric value.

I.e.

for (var i = count - 1; i >= 0; i--)
{
  // count is only evaluated once and then the comparison is always on 0.
}

Thanks in advance to anyone who can satisfy my professional curiorisity!

+2  A: 

The way you're doing it now isn't faster (apart from it being an indefinite loop, I guess you meant to do i--.

If you want to make it faster do:

for (i = 10; i--;) {
    //super fast loop
}

of course you wouldn't notice it on such a small loop. The reason it's faster is because you're decrementing i while checking that it's "true" (it evaluates to "false" when it reaches 0)

peirix
Are you missing a semi-colon? `(i = 10; i--;)`
searlea
Yes yes, I fixed the mistake. And if we're going to be picky I'll point out you forgot your semi colon after your i--! Heh.
GenericTypeTea
touché!
peirix
Why would that be faster? Shorter source doesn't mean it will be faster. Have you measured it?
Greg Hewgill
Yes, I have measured it, and I'm not saying shorter source makes it faster, but fewer operations makes it faster.
peirix
+3  A: 

It can be explained by JavaScript (and all languages) eventually being turned into opcodes to run on the CPU. CPUs always have a single instruction for comparing against zero, which is damn fast.

As an aside, if you can guarantee count is always >= 0, you could simplify to:

for (var i = count; i--;)
{
  // whatever
}
searlea
Shorter source code doesn't necessarily mean it will be faster. Have you measured it?
Greg Hewgill
Ooops I missed this one. Nail on the head there chap.
Robert
I'd like to see the assembly sources where comparing against 0 is different. It's been a few years, but at one time I did a ton of assembly coding and I can't for the life of me think of a way to do a compare/test against 0 in a way that can't be equally as fast for any other integer. Yet, what you say does ring true. Frustrated that I can't figure out why!
Brian Knoblauch
Any references anywhere supporting this so I can do a bit of reading?
GenericTypeTea
@Brian Knoblauch: If you use an instruction such as "dec eax" (x86 code) then that instruction automatically sets the Z (zero) flag which you can immediately test without having to use another compare instruction in between.
Greg Hewgill
@Brian For any other integer you'd have the overhead of pulling the value out of memory and loading it into a register. The Intel instruction set (as an example) has a shed-load of 'if zero' functionality for jumping and looping. Google for 'intel instruction set manual' if you want thousands of pages of documentation to wade through.
searlea
When interpretting Javascript, I doubt that opcodes are going to be the bottleneck, though. More likely to be that less tokens means the interpreter can process the source code faster.
Todd Owen
@Greg Hewgill - Thanks! I had completely forgotten that decrementing the accumulator sets flags too!
Brian Knoblauch
-1. Most Javascript engines don't actually generate machine code on the fly, so this is irrelevant.
Artelius
+3  A: 

The best approach to answering this sort of question is to actually try it. Set up a loop that counts a million iterations or whatever, and do it both ways. Time both loops, and compare the results.

The answer will probably depend on which browser you are using. Some will have different results than others.

Greg Hewgill
That still wouldn't answer his question on _why_ it's faster. He'd just get a benchmark, without any knowledge of why it is that way...
peirix
What peirix said.
GenericTypeTea
That's true. However, without knowing the exact implementation of each Javascript engine in each browser, it's nearly impossible to answer the "why" part. A lot of the answers here throw around anecdotal recommendations like "use predecrement instead of postdecrement" (a C++ optimisation trick) and "compare against zero" which might be true in native code compiled languages but Javascript is pretty far from the bare metal of the CPU.
Greg Hewgill
+30  A: 

This guy compared a lot of loops in javascript, in a lot of browsers. He also has a test suite so you can run them yourself.

In all cases (unless I missed one in my read) the fastest loop was:

var i = arr.length; //or 10
while(i--)
{
  //...
}
Tom Ritter
+1 for actual benchmark code.
Greg Hewgill
+1 interesting comparing, thanks for the url
Amr ElGarhy
+1 Excellent results! Some interesting reading.
GenericTypeTea
Nice :)But there is no backward "for"-loop tested... But the for loops mentioned by peirix or searlea should be pretty much the same as the "while" loop with "i--" as its condition. And that was the fastest loop tested.
Gushiken
Interesting, but I wonder if pre-decrement would be even faster. Since it won't have to store the intermediate value of i.
tvanfosson
...to be clear var i arr.length + 1; while (--i) { }
tvanfosson
If I remember correctly, my hardware-course prof said, that test for 0 or not 0 is fastest possible "calculation". In while(i--) the test is always a test for 0. Maybe that's why this is fastest?
StampedeXV
@StampedeXV: Yep, that's why it's considered the fastest. Interestingly, when I ran the benchmark that @Tom linked to, the reverse loop didn't come out any faster than the normal `for` loop, but that might just be because of the small amount of iterations.
musicfreak
A: 

Using the prefix increment operator is somewhat faster. With the postfix, the compiler must retain the previous value as the result of the expression.

for (var i = 0; i < n; ++i) {
  do_stuff();
}

A smart interpreter or compiler will see that the result of i++ is not used and not store the result of the expression, but not all js engines do.

Jeff Ober
How do you know that the prefix operation is "somewhat" faster? Have you measured it?
Greg Hewgill
Really, it depends on the implementation. Without compiler optimization, it requires less work, since it need not keep a copy of the old value to return as the result of the expression.
Jeff Ober
A: 

Love it, lots of marks up but no answer :D

Simply put a comparison against zero is always the fastest comparison

So (a==0) is actually quicker at returning True than (a==5)

It's small and insignificant and with 100 million rows in a collection it's measurable.

i.e on a loop up you might be saying where i <= array.length and be incrementing i

on a down loop you might be saying where i >= 0 and be decrementing i instead.

The comparison is quicker. Not the 'direction' of the loop.

Robert
There is no answer to the question as stated because Javascript engines are all different and the answer depends on exactly which browser you're measuring it on.
Greg Hewgill
No it's fundamentally accepted comparisons against zero are the quickest. Although your statements are correct as well the golden rule of comparing against zero is absolute.
Robert
That's true *only* if the compiler chooses to make that optimisation, which is certainly not guaranteed. The compiler might generate exactly the same code for (a==0) and (a==5), except for the value of the constant. A CPU won't compare against 0 any more quickly than against any other value, if both sides of the comparison are variables (from the point of view of the CPU). Generally only native code compilers have the opportunity to optimise at this level.
Greg Hewgill
+2  A: 

In many cases, this has essentially nothing to do with the fact that processors can compare to zero faster than other comparisons.

This is because only a few Javascript engines (the ones in the JIT list) actually generate machine language code.

Most Javascript engines build an internal representation of the source code which they then interpret (to get an idea of what this is like, have a look near the bottom of this page on Firefox's SpiderMonkey). Generally if a piece of code does practically the same thing but leads to a simpler internal representation, it will run faster.

Bear in mind that with simple tasks like adding/subtracting one from a variable, or comparing a variable to something, the overhead of the interpreter moving from one internal "instruction" to the next is quite high, so the less "instructions" that are used internally by the JS engine, the better.

Artelius