Why are the Math functions so insanely slow?


import flash.utils.getTimer;
var n:Number = 1.5;
var st:Number = getTimer();
var test:int;

function divT():void {    
    st = getTimer();
    for(var i:int=0;i<10000000;i++) {
        test = Math.floor(n);
    }
    trace("Time spent calculating with Math.Floor: " +(getTimer()-st)+ " ms");
}

function divB():void {    
    st = getTimer();
    for(var i:int=0;i<10000000;i++) {
        test = int(1.5);
    }
    trace("Time spent calculating with conversion to int: " +(getTimer()-st)+ " ms");
}

divT();
divB();

Whereas I see and understand the results, I don’t get why the built in floor function is so incredibly slow compared to int conversion.

Can anyone shed some light on this?

For those that don’t feel like trying it, this is what it traces out for me;


Time spent calculating with Math.Floor: 721 ms
Time spent calculating with conversion to int: 34 ms

I believe this is the code (it’s not AS, obviously) used for [FONT=“Courier New”]Math.floor()[/FONT]:


#include "fdlibm.h"

#ifdef __STDC__
static const double really_big = 1.0e300;
#else
static double really_big = 1.0e300;
#endif

#ifdef __STDC__
	double fd_floor(double x)
#else
	double fd_floor(x)
	double x;
#endif
{
        fd_twoints u;
	int i0,i1,j0;
	unsigned i,j;
        u.d = x;
	i0 =  __HI(u);
	i1 =  __LO(u);
	j0 = ((i0>>20)&0x7ff)-0x3ff;
	if(j0<20) {
	    if(j0<0) { 	/* raise inexact if x != 0 */
		if(really_big+x>0.0) {/* return 0*sign(x) if |x|<1 */
		    if(i0>=0) {i0=i1=0;} 
		    else if(((i0&0x7fffffff)|i1)!=0)
			{ i0=0xbff00000;i1=0;}
		}
	    } else {
		i = (0x000fffff)>>j0;
		if(((i0&i)|i1)==0) return x; /* x is integral */
		if(really_big+x>0.0) {	/* raise inexact flag */
		    if(i0<0) i0 += (0x00100000)>>j0;
		    i0 &= (~i); i1=0;
		}
	    }
	} else if (j0>51) {
	    if(j0==0x400) return x+x;	/* inf or NaN */
	    else return x;		/* x is integral */
	} else {
	    i = ((unsigned)(0xffffffff))>>(j0-20);
	    if((i1&i)==0) return x;	/* x is integral */
	    if(really_big+x>0.0) { 		/* raise inexact flag */
		if(i0<0) {
		    if(j0==20) i0+=1; 
		    else {
			j = i1+(1<<(52-j0));
			if((int)j<i1) i0 +=1 ; 	/* got a carry */
			i1=j;
		    }
		}
		i1 &= (~i);
	    }
	}
        u.d = x;
	__HI(u) = i0;
	__LO(u) = i1;
        x = u.d;
	return x;
}

With that much manipulation and evaluation it’s no surprise that it takes a while. All the [FONT=“Courier New”]int() [/FONT]function does is return the number before the ‘.’ - that can’t be a very complex function. (Try [FONT=“Courier New”]trace(int(1.999));[/FONT] for example, it still returns ‘1’.)

Well… try trace(Math.floor(1.9999));

:wink:


trace(int(-1.5)); //traces -1
trace(Math.floor(-1.5)); //traces -2

:slight_smile: