Actionscript Optimizations (Including Bitwise Ones)

The following information is a collective update of some posts I remember reading in the past. Finding them is always difficult. So I decided to collate them into a single post. The idea is to minimize the information into a reference format, instead of explaining everything. Some of the optimisations are moot when dealing with later versions of AS3, but I want them here for allowing me to test this functionality in other languages as well. It is just a nice place to group everything for quick reference. Some of them are AS3 specific, but most can be applied elsewhere.

Smaller variable sizes increase performance

for (var i:Number = 0; i < 50; i++) {}

is slower than

for (var i:int = 0; i < 50; i++) {}

 

Accessing variables in other classes has overhead

for (var i:int = 0; i < 1000; i++) {
    var = SomeClass.SOME_CONSTANT;
}

is slower than

var myConst:int = SomeClass.SOME_CONSTANT;
for (var i:int = 0; i < 1000; i++) {
   var = myConst;
}

 

Multiple variable instantiation

For some reason

for (var i:int=0; i < 100000; i++) {
    var v1:Number=10;
    var v2:Number=10;
    var v3:Number=10;
    var v4:Number=10;
    var v5:Number=10;
}

is significantly slower than

for (var i:int=0; i < 100000; i++) {
    var v1:Number=10, 
        v2:Number=10, 
        v3:Number=10, 
        v4:Number=10, 
        v5:Number=10;
}

 

Bitwise for multiplication and division

The following only really works with division and multiplication in powers of 2

var i:int = 4 * 2;
i = 4 * 4;
i = 4 / 2;
i = 4 / 4;

is slower than

var i:int = 4 << 1;
i = 4 << 2;
i = 4 >> 1;
i = 4 >> 2;

 

Integer Addition / Subtraction

a = a + 1;
b = b - 1;

might be slower than

a += 1;
b -= 1;

which in turn might be slower than

a++;
a--;

 

Division is slower than multiplication

= 20 / 5;

is slower than

= 20 * 0.25;

 

Math.floor / Math.ceil

Casting can be faster than the method calls e.g.

var floor:int = int(1.5); // = 1
// only works with positive numbers
// Math.floor(-1.5) = 2 whereas int(-1.5) = -1

var ceil:int = int(1.5) + 1; // = 2
// only works on fractions int(1.0) + 1 = 2
// whereas Math.ceil(1.0) = 1

For safety sake I would consider only using the above if performance is extremely critical. The following might be a wiser alternative.

floor = num >> 0;
ceil = num == int(num) ? num : int(num) + 1;

 

Color extraction

// 32 bit
var color:uint = 0xFF112233; // 0xAARRGGBB
var a:uint = color >> 24; // only need to shift
var r:uint = color >> 16 & 0xFF; // shift and mask
var g:uint = color >> 8 & 0xFF; // shift and mask
var b:uint = color >> 0 & 0xFF; // shift and mask

 

Color combination

var color:uint = a << 24 | r << 16 | g << 8 | b;

 

Swapping integers (no temp var)

var temp:int = a;
a = b;
b = temp;

is slower than

a ^= b;
b ^= a;
a ^= b;

 

Flipping sign using NOT / OR

i = -i;

is slower than

i = ~i + 1;
// or
i = (i ^ -1) + 1;

 

Modulo ops with Bitwise AND

var x:int = num % 4;

is slower than

var x:int = num & (4-1);

* this only works with divisors in powers of 2

 

Determining even / uneven

var isEven:Boolean = (i % 2) == 0;

is slower than

var isEven:Boolean = (i & 1) == 0;

 

Absolute value

var i:int = Math.abs(value);

is slower than

var i:int = x < 0 ? -x : x;

is slower than

var i:int = (x ^ (x >> 31)) - (x >> 31);

* although I think the last line is on a 32bit number

 

Comparing integers for sign equality

var eqSign:Boolean = a * b > 0;

is slower than

var eqSign:Boolean = a ^ b >= 0;

 

Color conversions from R5G5B5 to R8G8B8

R8 = (R5 << 3) | (R5 >> 2);
G8 = (G5 << 3) | (G5 >> 2);
B8 = (B5 << 3) | (B5 >> 2);

 

Simplifying logic

var ctrl : Boolean = event.ctrlKey;
var alt : Boolean = event.altKey;
var shift : Boolean = event.shiftKey;

if (!shift && !alt && ctrl) {
    // CTRL
}
else if (!shift && alt && !ctrl) {
    // ALT
}
else if (!shift && alt && ctrl) {
    // CTRL-ALT
}
else if (shift && !alt && !ctrl) {
    // SHIFT
}
else if (shift && !alt && ctrl) {
    // CTRL-SHIFT
}
else if (shift && alt && !ctrl) {
    // SHIFT-ALT
}
else if (shift && alt && ctrl) {
    // CTRL-SHIFT-ALT
}

can become easier with a function

private static function getFlags(event : KeyboardEvent) : uint {
    var flags : uint = 0;
    flags += (event.ctrlKey) ? 1 : 0;
    flags += (event.altKey) ? 2 : 0;
    flags += (event.shiftKey) ? 4 : 0;

    return flags;
}

and a switch

switch ( getFlags(event) ) {
case 1: // CTRL
    break;
case 2: // ALT
    break;
case 3: // CTRL-ALT
    break;
case 4: // SHIFT
    break;
case 5: // CTRL-SHIFT
    break;
case 6: // SHIFT-ALT
    break;
case 7: // CTRL-SHIFT-ALT
    break;
}

and the following can be done to determine if a bit is on or off

if (getFlags(event) & 4 == 4) { // apply mask and test
    // shift enabled
}

 

References

 

explanation on Bitwise operations