FastMath class

Just a simple utility class I created for my current project. It keeps a lookup table of all the trig values and square root values, etc. so that it is only a simple lookup operation and it doesn’t have to calculate anything. You can adjust the resolution of the trig and square root functions and the maximum argument the square root function can handle depending on your memory limitations. Feel free to extend it. Let me know what you think :slight_smile:

public final class FastMath{
	public static final float PI=3.1415926535897932384626433832795028841971f;
	public static final float DEGRAD=PI/180f, RADDEG=180f/PI;
	private static final float TRIG_RES=DEGRAD*0.1f, SQRT_RES=0.1f, SQRT_MAX=10000f;
	private static float[] sin, cos, tan, asin, acos, atan, sqrt;
	private static boolean initialized=false;
	public static final void initialize(){
		sin=new float[(int)(2f*PI/TRIG_RES)];
		cos=new float[(int)(2f*PI/TRIG_RES)];
		tan=new float[(int)(2f*PI/TRIG_RES)];
		asin=new float[(int)(2f*PI/TRIG_RES)];
		acos=new float[(int)(2f*PI/TRIG_RES)];
		atan=new float[(int)(2f*PI/TRIG_RES)];
		for(int i=0;i<sin.length;i++){
			sin[i]=(float)Math.sin(i*TRIG_RES);
			cos[i]=(float)Math.cos(i*TRIG_RES);
			tan[i]=(float)Math.tan(i*TRIG_RES);
			asin[i]=(float)Math.asin(i*TRIG_RES);
			acos[i]=(float)Math.acos(i*TRIG_RES);
			atan[i]=(float)Math.atan(i*TRIG_RES);
		}
		sqrt=new float[(int)(SQRT_MAX*(1f/SQRT_RES))];
		for(int i=0;i<sqrt.length;i++){
			sqrt[i]=(float)Math.sqrt(i*SQRT_RES);
		}
		initialized=true;
	}
	public static final float sin(float i){
		if(!initialized) initialize();
		return sin[(int)(i/TRIG_RES)%sin.length];
	}
	public static final double sin(double i){
		if(!initialized) initialize();
		return (double)sin[(int)(i/TRIG_RES)%sin.length];
	}
	public static final float cos(float i){
		if(!initialized) initialize();
		return cos[(int)(i/TRIG_RES)%sin.length];
	}
	public static final double cos(double i){
		if(!initialized) initialize();
		return (double)cos[(int)(i/TRIG_RES)%sin.length];
	}
	public static final float tan(float i){
		if(!initialized) initialize();
		return tan[(int)(i/TRIG_RES)%sin.length];
	}
	public static final double tan(double i){
		if(!initialized) initialize();
		return (double)tan[(int)(i/TRIG_RES)%sin.length];
	}
	public static final float asin(float i){
		if(!initialized) initialize();
		return asin[(int)(i/TRIG_RES)%sin.length];
	}
	public static final double asin(double i){
		if(!initialized) initialize();
		return (double)asin[(int)(i/TRIG_RES)%sin.length];
	}
	public static final float acos(float i){
		if(!initialized) initialize();
		return acos[(int)(i/TRIG_RES)%sin.length];
	}
	public static final double acos(double i){
		if(!initialized) initialize();
		return (double)acos[(int)(i/TRIG_RES)%sin.length];
	}
	public static final float atan(float i){
		if(!initialized) initialize();
		return atan[(int)(i/TRIG_RES)%sin.length];
	}
	public static final double atan(double i){
		if(!initialized) initialize();
		return (double)atan[(int)(i/TRIG_RES)%sin.length];
	}
	public static final float abs(float i){
		return (i<0?-i:i);
	}
	public static final double abs(double i){
		return (i<0?-i:i);
	}
	public static final int abs(int i){
		return (i<0?-i:i);
	}
	public static final float sqrt(float i){
		if(!initialized) initialize();
		return sqrt[(int)(i/SQRT_RES)%sqrt.length];
	}
	public static final double sqrt(double i){
		if(!initialized) initialize();
		return (double)sqrt[(int)(i/SQRT_RES)%sqrt.length];
	}
	public static final float toDegrees(float rad){
		return rad*180f/PI;
	}
	public static final double toDegrees(double rad){
		return rad*180f/PI;
	}
	public static final float toRadians(float deg){
		return deg*PI/180f;
	}
	public static final double toRadians(double deg){
		return deg*PI/180f;
	}
	
}

why not use Math.round(Math.PI) ? It would be most precise PI as float. Also there are toDegrees and toRadians as I remember in Math, probably more precise and faster then PI/180f and 180f/PI.

I forgot that I typed in PI, I just did that because I memorized it to over 100 places and I wanted it to be as exact as possible. Unless Math.PI goes to more than 100 places…

Interesting sidenote: By only using PI to 47 places it would be possible to accurately draw a circle around the known universe, accurate to the width of an atom.

Compare your code:


	public static final float sin(float i){
		if(!initialized) initialize();
		return sin[(int)(i/TRIG_RES)%sin.length];
	}

To this:


   public static final float sin(float rad)
   {
      return sin[(int) (rad * radToIndex) & SIN_MASK];
   }

You can get rid of these:
1 if-statement (30 cycles)
1 division (8 cycles)
1 modulo (8 cycles)

I would do the init stuff in a static block and be done with it.

Also checkout the abs thread of doom:
http://www.java-gaming.org/forums/index.php?topic=12543.0

as javadoc says, Math.PI is most accurate PI estimate that you can put into double, with that logic Math.round(Math.PI) should be most accurate value of PI in float.

you mean a sphere probably…

c’mon really, optimizing abs!? … while it could be fun it’s pointless

Math.round(3.141596…) = 3

not exactly accurate ::slight_smile:

Didn’t you just mean:
(float)Math.PI;
?

you should replace i/TRIG_RES everywhere it appears by i*ITREG_RES with ITREG_RES initialised to 1/TRIG_RES maybe it will also be much faster by using integer as index rather than double and using power of two for the resolution

lets say that resolution is 65536 for 16bit

to index your array you can than do something like that:

ITREG_RES=65536/TRIG_RES;

and

int ii=(int)i*65536; 
((ii*ITREG_RES)>>16)&0xFFFF;

example:

sin[(int)(i/TRIG_RES)%sin.length]

replaced by

sin[((ii*ITREG_RES)>>16)&0xFFFF]

i guess it will be much faster

nb: I did not try this solution, it may work unproperly, if you try it, let me know!

eh… I though rounding a double gives you a float… don’t know why :slight_smile: … it gives long, while rounding float gives int. So I guess
(float)Math.PI is closest PI as float

another thing you can do is to replace :

rad*180f/PI

by

rad*idegPI;

with idegPI initialized only once :

float idegPI=(float)(180.0/Math.PI)

and the same for deg*PI/180

EDIT: sorry, i just see that riven already mention this optimisation with radToIndex

good work bert!

it would be interesting if you would have any comparisons on how much faster it really is than regular Math.*

thanks!