I was talking to John Grden about some geeky math stuff and I dropped one of my favorite little optimization tricks on him: the idea that Math.PI is a constant and 180 is a constant, and when you code 180/Math.PI or Math.PI/180, this gets evaluated at compile time, and the numerical value is inserted into directly into the byte code. So, if you do a calculation like this:
var myangle = a * 180 / Math.PI;
it will be faster than doing this:
var toDegrees:Number = 180 / Math.PI;
var myangle = a * toDegrees;
because in the second case, toDegrees has to be evaluated at runtime, whereas in the first case, 180 / Math.PI is hardcoded in the bytecode. Of course, the initial value of toDegrees is a constant, but because toDegrees is a variable, it is possible it could change, so the runtime needs to look up the value when it is encountered.
So, naturally, John gets a flashon about this and tries it out in AS3 with the following code:
[as]var toDegrees:Number = 180/Math.PI;
function runTest0() {
var time:Number = getTimer();
var a:Number = 90;
for (var i:Number = 0; i<100000; i++) { var myangle = a180/Math.PI; } trace((getTimer()-time)/1000); } function runTest1() { var time:Number = getTimer(); var a:Number = 90; for (var i:Number = 0; i<100000; i++) { var myangle = atoDegrees; } trace((getTimer()-time)/1000); } runTest0(); runTest1();[/as] Now, per my understanding, test0 should run faster, as it’s using the constants, and test1 should be slower because it’s got to do a lookup of toDegrees at run time. Oddly enough, though, test1 runs on average twice as fast as test0! I also tried making toDegrees a const instead of a var. I could understand this being faster, but it actually seems to make no difference at all. He’s just blown away something I believed in. This is like finding out there is no Santa Claus… OK, not quite that traumatic, but still, I was shocked. So I try the same code in AS2, and some faith is restored. In AS2, test0 takes about 85% of the time test1 takes. That’s what I expected. Really odd that AS3 is opposite though. My off the cuff guess is that this has something to to with the JIT optimizing stuff into low level code, seeing that the value is called thousands of times without being changed, thus it knows it can use the same value. But this is something I know relatively little about, so I could just be talking out of my … inexperience. If anyone has some more insight into this, we’d love to know what’s really going on. But, getting back to the title of the post, don’t take your old optimization tricks from AS1/2 and assume they are going to work in AS3. It’s a whole new ball game. [ADDENDUM] I just modified the code to make the initial angle a random number, like so: [as]const toDegrees:Number = 180/Math.PI; function runTest0() { var time:Number = getTimer(); var a:Number = 180; for (var i:Number = 0; i<100000; i++) { var myangle = Math.random() * 360 *180/Math.PI; } trace((getTimer()-time)/1000); } function runTest1() { var time:Number = getTimer(); var a:Number = 180; for (var i:Number = 0; i<100000; i++) { var myangle = Math.random() * 360 *toDegrees; } trace((getTimer()-time)/1000); } runTest0(); runTest1();[/as] In this case, the results are dead even. Veeeeeery interesting.