This is a quick article to discuss a point brought up in a recent comment. Which is the fastest way to increment: j++, ++j, or j+=1? Likewise, which is the fastest way to decrement? Below I will dispel the myth that there is any difference between them at all.
Here is what the comment claimed:
Also, for what it’s worth I hear (i += 1) is faster than (i++) in ActionScript.
This has been discussed elsewhere, too: FlashKit (no conclusion) and Kirupa (various claims). I don’t know why a decent performance test was never done, but I made one quite easily:
package { import flash.text.*; import flash.utils.*; import flash.display.*; public class IncrementDecrementTest extends Sprite { private var __logger:TextField; public function IncrementDecrementTest() { __logger = new TextField(); __logger.autoSize = TextFieldAutoSize.LEFT; addChild(__logger); const NUM_ITERATIONS:int = 100000000; var i:int; var j:int; var beforeTime:int; log("Increment:"); j = 0; beforeTime = getTimer(); for (i = 0; i < NUM_ITERATIONS; ++i) { j++; } log("\tPost-increment (j++): " + (getTimer()-beforeTime)); j = 0; beforeTime = getTimer(); for (i = 0; i < NUM_ITERATIONS; ++i) { ++j; } log("\tPre-increment (++j): " + (getTimer()-beforeTime)); j = 0; beforeTime = getTimer(); for (i = 0; i < NUM_ITERATIONS; ++i) { j += 1; } log("\tAdd 1 (j+=1): " + (getTimer()-beforeTime)); log("Decrement:"); j = int.MAX_VALUE; beforeTime = getTimer(); for (i = 0; i < NUM_ITERATIONS; ++i) { j--; } log("\tPost-decrement (j--): " + (getTimer()-beforeTime)); j = int.MAX_VALUE; beforeTime = getTimer(); for (i = 0; i < NUM_ITERATIONS; ++i) { --j; } log("\tPre-decrement (--j): " + (getTimer()-beforeTime)); j = int.MAX_VALUE; beforeTime = getTimer(); for (i = 0; i < NUM_ITERATIONS; ++i) { j -= 1; } log("\tSubtract 1 (j-=1): " + (getTimer()-beforeTime)); } private function log(msg:*): void { __logger.appendText(msg + "\n"); } } }
Here are my results:
| Environment | Post-Increment | Pre-increment | Add One | Post-Decrement | Pre-Decrement | Subtract One |
|---|---|---|---|---|---|---|
| 3.0 Ghz Intel Core 2 Duo | 236 | 236 | 236 | 236 | 236 | 236 |
There is no difference at all, even with one hundred million operations. So just use whichever you prefer.
#1 by Simon Richardson on March 5th, 2010 · | Quote
I see a massive difference in the Debug player, but this shouldn’t be used for Performance testing, so we can ignore this. I think people forget to switch to normal player when testing this stuff, which is why people see them as a performance difference.
I do get this though running 1000000000 iterations in the standalone (the debug player wouldn’t play this!). As you can see there is absolutely no real difference because the differences are so tight.
Increment:
Post-increment (j++): 2771
Pre-increment (++j): 2778
Add 1 (j+=1): 2814
Decrement:
Post-decrement (j–): 2776
Pre-decrement (–j): 2864
Subtract 1 (j-=1): 2839
#2 by Sindisil on March 5th, 2010 · | Quote
Your test misses an one aspect of the increment and decrement operators: the different semantics of the pre-fix and post-fix versions.
The value of the expression ++i is the value of ‘i’ after increment.
The value of the expression i++ is the value of ‘i’ before it is incremented.
The decrement operator has analogous semantics.
This means that the interpreter, or the code generated by the AVM2 JIT, must make a copy of the original value of the variable operated upon in the post-fix cases. This takes non-zero time.
In the case where the value of the increment or decrement expression is not used, the interpreter or JIT is free to optimize away the saving of the original value.
Changing the increment and decrement test stanzas to include assignment (e.g. change from “j++” to “acc = j++” and “++j” to “acc = ++j”) results in a difference in performance, albeit a minor one
My results on my netbook, running latest FP 10 release player in Firefox:
Increment:
Post-increment (j++): 659
Pre-increment (++j): 644
Decrement:
Post-decrement (j–): 647
Pre-decrement (–j): 584
#3 by jackson on March 5th, 2010 · | Quote
This is a good point. My test only applies to simple increments and decrements where the value of the expression is not used. This is probably most uses though. Nevertheless, thanks for explaining this and providing your test results!
#4 by Sindisil on March 5th, 2010 · | Quote
Yup, the bottom line is, it seldom matters – use the incr/decr form that’s most comfortable.
Frankly, given the many other optimization opportunities that AS3 misses, I was mildly surprised that, when it’s safe to, AVM2 optimizes away the temporary.
It’s also important to note that the difference in performance, even when there is one, is too small to matter in the context of AS3. We’re talking, at most, 50ms over 100,000,000 repetitions.
I just thought it was worth highlighting the different scenarios.