Actionscript 3: Faster Math.floor and Math.ceil using int typecast
Posted November 19, 2010 by Nick Vogt in Programming
In order to use int typecasting in place of Math.floor or Math.ceil, you must first understand exactly what these functions do: Math.floor takes a number and returns the next lowest whole integer. Passing 0.9 will return 0 and -0.9 will return -1. Math.ceil returns the next highest integer, so will return 1 from 0.9 and 0 from -0.9. This is different than truncating, which would return 0 in all cases, and is why typecasting using int (usually used to truncate) wouldn't seem to work at first.
In order to make int typecasting work, you need to add a condition check to see if the number is negative or positive (negative for floor, positive for ceil), and adjust it by 1 if it is. Why do this instead of just using Math.floor or Math.ceil? Because it is faster and you can avoid a function call if desired. Look at these examples:
Using Math.floor like normal requires 691 milliseconds for this run:
Now using a custom floor function:
The above took 601 milliseconds to process. Now you may wonder if the savings are worth the effort of having the extra function, and in some cases I would say no. But that's not where the real performance advantage is to be had. By using int typecasting and the condition, you can avoid the use of a function altogether, and do something like this:
The above only took 113 milliseconds to process.
Here is the code for finding the ceiling:
Notice that I checked to see if the original number is greater than 0, and if so added 1.
In order to make int typecasting work, you need to add a condition check to see if the number is negative or positive (negative for floor, positive for ceil), and adjust it by 1 if it is. Why do this instead of just using Math.floor or Math.ceil? Because it is faster and you can avoid a function call if desired. Look at these examples:
Using Math.floor like normal requires 691 milliseconds for this run:
var i:int = 0;
var testVar:Number = -82.20035;
var floored:Number;
var time1 = new Date();
for(i = 0; i < 5000000; i ++)
{
floored = Math.floor(testVar);
}
var time2 = new Date();
trace(time2 - time1);
var testVar:Number = -82.20035;
var floored:Number;
var time1 = new Date();
for(i = 0; i < 5000000; i ++)
{
floored = Math.floor(testVar);
}
var time2 = new Date();
trace(time2 - time1);
Now using a custom floor function:
var i:int = 0;
var testVar:Number = 82.20035;
var floored:Number;
var time1 = new Date();
for(i = 0; i < 5000000; i ++)
{
floored = floor(testVar)
}
var time2 = new Date();
trace(time2 - time1);
function floor(n:Number):Number
{
if(n < 0) n-= 1;
return int(n);
}
var testVar:Number = 82.20035;
var floored:Number;
var time1 = new Date();
for(i = 0; i < 5000000; i ++)
{
floored = floor(testVar)
}
var time2 = new Date();
trace(time2 - time1);
function floor(n:Number):Number
{
if(n < 0) n-= 1;
return int(n);
}
The above took 601 milliseconds to process. Now you may wonder if the savings are worth the effort of having the extra function, and in some cases I would say no. But that's not where the real performance advantage is to be had. By using int typecasting and the condition, you can avoid the use of a function altogether, and do something like this:
var i:int = 0;
var testVar:Number = 82.20035;
var floored:Number;
var time1 = new Date();
for(i = 0; i < 5000000; i ++)
{
if(testVar < 0) floored = int(testVar - 1)
else floored = int(testVar);
}
var time2 = new Date();
trace(time2 - time1);
var testVar:Number = 82.20035;
var floored:Number;
var time1 = new Date();
for(i = 0; i < 5000000; i ++)
{
if(testVar < 0) floored = int(testVar - 1)
else floored = int(testVar);
}
var time2 = new Date();
trace(time2 - time1);
The above only took 113 milliseconds to process.
Here is the code for finding the ceiling:
if(testVar > 0) ceiling = int(testVar + 1)
else ceiling = int(testVar);
else ceiling = int(testVar);
Notice that I checked to see if the original number is greater than 0, and if so added 1.
| Series | ActionScript 3 Tutorials |
|---|---|
| Tags | actionscript 3 flash guide tutorial |
Comment on this post
Legacy Comments (2)
Nick | February 11, 2011 | 9:14 AM PST
I ran testing using getTimer() and new Date(), and the results varied. Sometimes one was higher than the other. I did find that getTimer() is more accurate for lower amounts (anything under 16ms). I'll try using getTimer() in future tests. Thanks!
Mateusz | February 11, 2011 | 4:00 AM PST
You should use getTimer() to measure execution time;)
