Faster floor, round, ceil for ActionScript
It is always nice to add some speed boost to your performance critical algorithms. Making some native Math function’s alternatives perform up to 8 times faster is possible. Lets have a look at the basic ones Math.floor(), Math.round(), Math.ceil():
faster alternative for Math.floor()
var ni:int = n; return (n < 0 && n != ni) ? ni - 1 : ni;
faster alternative for Math.round()
return n < 0 ? n + .5 == (n | 0) ? n : n - .5 : n + .5;
faster alternative for Math.ceil()
var ni:int = n; return (n >= 0 && n != ni) ? ni + 1 : ni;
Here is an app runnig some unit tests and speed tests. I have wrapped both custom methods and Math methods into functions and count out empty method call time to correct the results.
Faster ceil, round, floor – wonderfl build flash online
The results talks for itself:
Math.floor(): 844 ms floor(): 125 ms Math.round(): 859 ms round(): 109 ms Math.ceil(): 766 ms ceil(): 93 ms
Where to go from here:
[...] This post was mentioned on Twitter by Klas Lundberg. Klas Lundberg said: RT @jozefchutka: Faster floor, round, ceil for ActionScript http://blog.yoz.sk/2011/01/faster-floor-round-ceil-for-actionscript/ [...]
great, I love this bitwise magic
sorry, for last comment, is too late – no bit operations was used, but good idea for me to try it …
Hello,
round doesn’t work for negative values:
trace(round(-12.3), Math.round(-12.3));
trace(round(-12.5), Math.round(-12.5));
trace(round(-12.7), Math.round(-12.7));
trace(round(12.3), Math.round(12.3));
trace(round(12.5), Math.round(12.5));
trace(round(12.7), Math.round(12.7));
// output
-12 -12
-13 -12
-13 -13
12 12
13 13
13 13
Hi Joe,
thank you for noticing… my tests were running wrong, when working with double-precision floating-points in actionscript there are some glitches like:
for(var n:Number=2;n>=-2;n-=.1) trace(n);
// outputs 2, 1.9, 1.7999999999999998 …
anyway I have updated round() method, and it should work ok now
Hey, I test it, it works great now!
For your glitches problem, I always use a dec10 function (round At 10 decimal place). It always save my life
for(var n:Number=2;n>=-2;n-=.1) trace(n, dec10(n));
public function dec10(value:Number):Number
{
return Math.round(value * 10000000000) / 10000000000;
}
Joe, thnx for the tip
Good stuff!
But what does (n | 0) mean in
“return n < 0 ? n + .5 == (n | 0) ? n : n – .5 : n + .5"?
As I understand bitwise OR (x | 0) always produce x. So what the point of doing (n | 0)?
hi Tmr,
n | 0 removes the decimal part. try 0.5 | 0 or -7.1 | 0
Hi very nice, but I can improve it a bit:) the round operation surely is missing the | 0 at the end, other wise the fraction stays e.g. 0.512 will be rounded to 1.012
/**
* Faster implementation of round operation
* the “| 0″ will remove fraction.
* @author Jozef Chúťka
* @param n
* @return
* @see http://blog.yoz.sk/2011/01/faster-floor-round-ceil-for-actionscript/
*/
public static function round(n:Number):Number
{
return (n < 0 ? (n + .5 == (n | 0) ? n : n – .5) : (n + .5)) | 0;
}
best regards
Hi Lukasz,
thanks for your suggestion. that totaly makes sense if you use Number as a return type, if you use int you do not need to add | 0
Hi,
and in example there was no casting or indicating of the type,
yes indeed, I want my method to match the original Math.round
best regards