Java-Gaming.org    
Featured games (79)
games approved by the League of Dukes
Games in Showcase (477)
Games in Android Showcase (109)
games submitted by our members
Games in WIP (536)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  3DzzD MathX class Accurate and Fast cos/sin  (Read 5558 times)
0 Members and 1 Guest are viewing this topic.
Offline DzzD
« Posted 2007-03-23 16:27:57 »

EDIT there is an updated version for MS JVM in this thread, this one will give weird result if used with Microsoft JVM!

Inspired by previous posts : "Fast Math post" and "Jeff reducing angle technic" , I decide to share a class I created for the 3DzzD Web 3D Engine.

I will run about 15 times faster for random angle input than the original Math.cos, it will also give more accurate results.


1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
64  
65  
66  
67  
68  
69  
70  
71  
72  
73  
74  
75  
76  
77  
78  
79  
80  
81  
82  
83  
84  
85  
86  
87  
88  
89  
90  
91  
92  
93  
94  
95  
96  
97  
98  
99  
package dzzd.utils;

/**
 *  MathX class.
 *  <br>
 * Base class used by 3DzzD Web 3D Engine to include faster and/or smarter maths functions<br>
 * <br>
 * <u>Some results comparaison between Math.cos and MathX.cos function, MathX.cos seems to be 0.5 to 20 times faster than Math.cos function and give more accurate results especially for PI/2</u><br>
  *<br>
 * <B>-PI</B><br>
 * MathX.cos(-Math.PI) =-1.0<br>
 * Math.cos(-Math.PI)  =-1.0<br>
 *<br>
 * <B>PI</B><br>
 * MathX.cos(Math.PI) =-1.0<br>
 * Math.cos(Math.PI)  =-1.0<br>
 *<br>
 * Root(2)/2=0.7071067811865476<br>
 * <B>PI/4</B><br>
 * MathX.cos(Math.PI*0.25) =0.7071067811865476<br>
 * Math.cos(Math.PI*0.25)  =0.7071067811865476<br>
 *<br>
 * <B>PI/2</B><br>
 * MathX.cos(Math.PI*0.25) =0.0<br>
 * Math.cos(Math.PI*0.25)  =6.123233995736766E-17<br>
 *<br>
 * <B>-PI/4</B><br>
 * MathX.cos(-Math.PI*0.25)=0.7071067811865476<br>
 * Math.cos(-Math.PI*0.25) =0.7071067811865476<br>
 *<br>
 * <B>-PI/2</B><br>
 * MathX.cos(-Math.PI*0.5) =0.0<br>
 * Math.cos(-Math.PI*0.5)  =6.123233995736766E-17<br>
 *<br>
 *  @author Bruno Augier (DzzD)
 *  @version 1.0, 01/03/07
 *  @since 1.0
 * @see IRender3D
 * @see IMesh3D
 * @see DzzD
 * @see <a href="http://dzzd.net/">http://dzzd.net/</a>
 */


public class MathX
{
   
   private static double f2=-0.5;
   private static double f4=-f2/(3.0*4.0);
   private static double f6=-f4/(5.0*6.0);
   private static double f8=-f6/(7.0*8.0);
   private static double f10=-f8/(9.0*10.0);
   private static double f12=-f10/(11.0*12.0);
   private static double f14=-f12/(13.0*14.0);
   private static double f16=-f14/(15.0*16.0);
   private static double f18=-f16/(17.0*18.0);
   private static double f20=-f18/(19.0*20.0);
   private static double PI=Math.PI;
   private static double PI2=2.0*PI;
   private static double PI05=0.5*PI;

   /**
   * Compute and return sinus of its parameter using taylor serie
   * @param x angle in radian to
   * @return sinus value for the given parameter
   */

   public static double sin(double x)
   {
      return cos(x-PI05);
   }

   /**
   * Compute and return cosinus of its parameter using taylor serie
   * @param x angle in radian to
   * @return cosinus value for the given parameter
   */
 
    public static double cos(double x)
    {
       if(x<0.0) x=-x;
       if(x<PI2)
       {
          if(x<PI)
          {  
            double x2=x*x;
            return 1.0+x2*(f2+x2*(f4+x2*(f6+x2*(f8+x2*(f10+x2*(f12+x2*(f14+x2*(f16+x2*(f18+x2*f20)))))))));      
         }
         else
         {
            x-=PI;
            double x2=x*x;
            return -(1.0+x2*(f2+x2*(f4+x2*(f6+x2*(f8+x2*(f10+x2*(f12+x2*(f14+x2*(f16+x2*(f18+x2*f20))))))))));      
         }
       }
       x%=PI2;
       x-=PI;
      double x2=x*x;
      return -(1.0+x2*(f2+x2*(f4+x2*(f6+x2*(f8+x2*(f10+x2*(f12+x2*(f14+x2*(f16+x2*(f18+x2*f20))))))))));
   }  
     
}

Online Riven
« League of Dukes »

JGO Overlord


Medals: 757
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #1 - Posted 2007-03-23 20:04:08 »

Nice mathematical approach, but how can this beat:

1  
2  
3  
   public static final float cos(float rad) {
      return cos[(int) (rad * radToIndex) & SIN_MASK];
   }


with 16 bits (64k table entries) it seems to be accurate enough for any (game) purpose

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Offline DzzD
« Reply #2 - Posted 2007-03-23 22:25:29 »

sorry but not enought accurate for me  Tongue

Lookup are good only on the last pass of a program, world and other transforms must be very very accurate, I already think that float are not enought accurate so lookup tables .... is not for me  Wink , exept fot the last pass of a renderer just before drawing.

Imagine a very huge world with very little object and very huge object lookup table will result in weird frame overlapped objects and such things.

In conclusion: offcourse lookup tables are faster but lookup tables are not used for the same goal.

notice:  I found recently that accessing an array randomly is a lot slower than accessing it sequentialy, anyway it is still a lot faster than compute cos using double.

note that double computation are done by the aritmetic coprocessor while the cpu continue to works.


Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline t_larkworthy

Senior Member


Medals: 1
Projects: 1


Google App Engine Rocks!


« Reply #3 - Posted 2007-04-14 01:01:08 »

Hmmmm. I just reinvented the wheel again. For some reason this post was not picked up on the search results, only the trig table fast math, which is not an approach I can use.
Anyway here is my FastMath class.
it implements cos sin acos asin and atan (probably should add tan for completness). Computes to arbitary precision for floats. I don't get a massive speedup for the sin and cos, so I will nick DzzDs, but at least a x5 performance gain on the inverse functions, even to the maximum precision. Its acos that is causing an issues with JOODE.

Quote
package net.java.dev.joode.util;

/**
 * A class implementing fast trig functions for floats.
 * Different precisions can be requested for the functions, sacrifising accuracy for speed.
 * cos and sin are only a little bit faster than the libraries counterparts,
 * but the inverse functions are about 5x as fast
 */
public class FastMath {
    public static final float PI = (float) Math.PI;
    public static final float halfPI = PI/2;


    public final static int MAX_EXPANSIONS = 100;
    static final int [] factorial = new int[MAX_EXPANSIONS];
    static final float [] factorial_recip = new float[MAX_EXPANSIONS];
    static final float [] recip = new float[MAX_EXPANSIONS];



    private static float precision;

    static{
        setPrecision(.0001f);

        calcFactorial();
        for (int i = 0; i < recip.length; i++) {
            recip = 1f/i;
        }
    }

    /**
     * iterates through the classic factorial function, filling in the values into the
     * factorial array. Note factorial(1) is stored in the array at index 1 to save constant adjustment
     * the recipricols are stored in facorial_recip
     */
    private static void calcFactorial() {
        int runningFactorial = 1;
        factorial[0]=1;
        factorial_recip[0]=1;
        for(int i=1;i<MAX_EXPANSIONS;i++){
            runningFactorial*=i;
            factorial = runningFactorial;
            factorial_recip = 1.0f/factorial;
        }
    }

    /**
     * returns x! only works upto x < MAX_EXPANSIONS
     * not really a general purpose implementation, this method is used for testing
     * @param x
     * @return
     */
    public static int factorial(int x){
        return factorial
  • ;
    }



    public static float sin(float x){
        while(x>PI) x-=Math.PI*2;
        while(x<-PI)x+=Math.PI*2;

        if(x> halfPI) return  cos(x-halfPI);
        if(x<-halfPI) return -cos(x+halfPI);

        //System.out.println("sin("+x+")");
        //sin(x) =x - x^3/3! + x^5/5! - x^7/7! + ... + xn.sin(n.pi/2)/n!

        //generate first term manually
        float term=x;
        float termABS=Math.abs(term);
        float pow=x;
        int n=1;
        int sign=1;

        float val = term;
       
        while(termABS > precision){
            //go up two each time
            n+=2;
            pow*=x*x;
            sign = sign==1?-1:1;//flip sign every time

            float oldTermABS = termABS;
            //calc next term
            term = sign * pow * factorial_recip[n];
            termABS = Math.abs(term);

            if(oldTermABS<termABS){
                //precision is worsening!
                //caused by pow getting very large, and
                //factorial getting very small
                break;//stop now, things are getting worse!
            }
            val += term;
        }
        return val;

    }

    public static float cos(float x){
        while(x>PI) x-=Math.PI*2;
        while(x<-PI)x+=Math.PI*2;

        if(x> halfPI) return -sin(x-halfPI);
        if(x<-halfPI) return  sin(x+halfPI);

        //System.out.println("cos("+x+")");
        //cos(x) = 1 - x2/2! + x4/4! - x6/6! + ...

        //generate first term manually
        float pow=x*x;
        int n=2;
        int sign=-1;
        float term=-pow*factorial_recip[2];
        float termABS=Math.abs(term);
        float val = 1+term;

        while(termABS > precision){
            //go up two each time
            n+=2;
            pow*=x*x;
            sign = sign==1?-1:1;//flip sign every time

            float oldTermABS = termABS;
            //calc next term
            term = sign * pow * factorial_recip[n];
            termABS = Math.abs(term);

            if(oldTermABS<termABS){
                //precision is worsening!
                //caused by pow getting very large, and
                //factorial getting very small
                break;//stop now, things are getting worse!
            }
            val += term;
        }
        return val;
    }

    public static float acos(float x){
        return halfPI - asin(x);
    }


    public static float asin(float x){
        float oldPrecision = precision;
        //you need to increase the precision becuase you multiply the result
        //of a call to atan
        precision = precision*.1f;
        //you would think that
        //the error would jsut need to be halved, becuase of the two
        //but for some strange reason nothing scales with the error correctly
        //but it does not seem to hurt the speed too much, so I put in a big change her
        float result = 2*atan((float) (x/(1+Math.sqrt(1-x*x))));
        precision = oldPrecision;
        return result;

    }


    public static float atan(float x){
        //http://en.wikipedia.org/wiki/Arctangent#Infinite_series
        //atan(x) = x - x^3/3 + x^5/5
        float pow=x;
        int n=1;
        int sign=1;
        float term=sign*pow*recip[n];
        float termABS=Math.abs(term);
        float val =term;

        while(termABS > precision){
            //go up two each time
            n+=2;
            pow*=x*x;
            sign = sign==1?-1:1;//flip sign every time

            float oldTermABS = termABS;
            //calc next term
            if(n<MAX_EXPANSIONS)
                term=sign*pow*recip[n];
            else
                term=sign*pow*1f/n;

            termABS = Math.abs(term);

            if(oldTermABS<termABS){
                //precision is worsening!
                //caused by pow getting very large, and
                //factorial getting very small
                break;//stop now, things are getting worse!
            }
            val += term;
        }
        return val;
    }

    public static void setPrecision(float precision) {
        FastMath.precision = precision;
    }
    public static float getPrecision() {
        return precision;
    }


}




 

Runesketch: an Online CCG built on Google App Engine where players draw their cards and trade. Fight, draw or trade yourself to success.
Offline t_larkworthy

Senior Member


Medals: 1
Projects: 1


Google App Engine Rocks!


« Reply #4 - Posted 2007-04-14 01:14:49 »

Actually I tried your version. It speeds up for precision over 1E-5, otherwise my version is faster (coz it is as lazy as possible at expanding the Taylors). On my computer my version at the most precise runs at: 159.2312 and your cos runs at 144, and sun's runs at 170.706. Acos though is my bottleneck anyway.

Tom

Runesketch: an Online CCG built on Google App Engine where players draw their cards and trade. Fight, draw or trade yourself to success.
Online Riven
« League of Dukes »

JGO Overlord


Medals: 757
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #5 - Posted 2007-04-14 01:24:08 »

sign = sign==1?-1:1; //flip sign every time
this saves you an if which are damn expensive
sign *= -1; //flip sign every time

and if you 'inline' the contents of Math.abs(), you will get very likely a significant speedup too

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Offline t_larkworthy

Senior Member


Medals: 1
Projects: 1


Google App Engine Rocks!


« Reply #6 - Posted 2007-04-14 17:53:47 »

Cheers for the tips. I added you sign tip. What do you mean by 'inline' ? Write my own version?

Runesketch: an Online CCG built on Google App Engine where players draw their cards and trade. Fight, draw or trade yourself to success.
Offline irreversible_kev

Junior Member





« Reply #7 - Posted 2007-04-14 18:47:13 »

I think he means, use

1  
if(oldTermABS<Math.abs(term)){


instead of

1  
2  
termABS = Math.abs(term);
if(oldTermABS<termABS){


etc ?
Offline t_larkworthy

Senior Member


Medals: 1
Projects: 1


Google App Engine Rocks!


« Reply #8 - Posted 2007-04-14 23:15:23 »

Would that really make any odds? Surely the compiler is smarter than that, plus I did not want to risk that value being recomputed for the while loop as well as the if?


Tom

Runesketch: an Online CCG built on Google App Engine where players draw their cards and trade. Fight, draw or trade yourself to success.
Offline t_larkworthy

Senior Member


Medals: 1
Projects: 1


Google App Engine Rocks!


« Reply #9 - Posted 2007-04-14 23:35:11 »

OK. I ran both optimization. My original versions are quicker in both cases. i.e. using the ? is quicker than integer multiplication, and storing the result of abs is better than recomputing it every time I need it.
Maybe this is not the case for everyone. I am running on a core duo. It be really nice to have a self optimizing FastMath class....

My basic benchmarker is below just in case anyone else want to play with the code, you will note that if you run acos to a higher precision than in the test block, that it starts to disagree with the libraries answers, I don't understand what the reason would be, unless I am technically adding the float in the wrong order (smallest first I think reduces numerical errors)
Tom
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
64  
65  
66  
67  
68  
69  
70  
71  
72  
73  
74  
75  
76  
77  
78  
79  
80  
81  
82  
83  
84  
85  
86  
87  
88  
89  
90  
91  
92  
93  
94  
95  
96  
97  
98  
99  
100  
101  
102  
103  
104  
105  
106  
107  
108  
109  
110  
111  
112  
113  
114  
115  
116  
117  
118  
119  
120  
121  
122  
123  
124  
125  
126  
127  
128  
129  
130  
131  
132  
133  
134  
135  
136  
137  
138  
139  
140  
141  
142  
143  
144  
145  
146  
147  
148  
149  
150  
151  
152  
153  
154  
155  
156  
157  
158  
159  
160  
161  
162  
163  
164  
165  
166  
167  
168  
169  
170  
171  
172  
173  
174  
175  
176  
177  
178  
179  
180  
181  
182  
183  
184  
185  
186  
187  
188  
189  
190  
191  
192  
193  
194  
195  
196  
197  
198  
199  
200  
201  
202  
203  
204  
205  
206  
207  
208  
209  
210  
211  
212  
213  
214  
215  
216  
217  
218  
219  
220  
221  
222  
223  
224  
package net.java.dev.joode.test.util;

import junit.framework.TestCase;
import net.java.dev.joode.util.FastMath;
import net.java.dev.joode.util.StopWatch;

/**
 */

public class FastMathTest extends TestCase {

    public void testFactorial(){
        assertTrue(FastMath.factorial(3) == 1*2*3);
        assertTrue(FastMath.factorial(4) == 1*2*3*4);
        assertTrue(FastMath.factorial(0) == 1);
    }

    public void testSin(){
        for(int i=0;i<1000;i++){
            float x = (float) (Math.random()*Math.PI*2);

            System.out.println("x = " + x);

            float precise = (float) Math.sin(x);
            float approx  = FastMath.sin(x);

            System.out.println("precise = " + precise);
            System.out.println("approx = " + approx);

            float error = Math.abs(precise-approx);

            assertTrue(error < FastMath.getPrecision());
        }
    }

    public void testCos(){
        for(int i=0;i<1000;i++){
            float x = (float) (Math.random()*Math.PI*2);

            System.out.println("x = " + x);

            float precise = (float) Math.cos(x);
            float approx  = FastMath.cos(x);

            System.out.println("precise = " + precise);
            System.out.println("approx = " + approx);

            float error = Math.abs(precise-approx);

            assertTrue(error < FastMath.getPrecision());
        }
    }

    public void testATan(){
        for(int i=0;i<1000;i++){
            float x = (float) (Math.random()*2-1);

            System.out.println("x = " + x);

            float precise = (float) Math.atan(x);
            float approx  = FastMath.atan(x);

            System.out.println("precise = " + precise);
            System.out.println("approx = " + approx);

            float error = Math.abs(precise-approx);

            assertTrue(error < FastMath.getPrecision());
        }
    }

    public void testACos(){
        for(int i=0;i<1000;i++){
            float x = (float) (Math.random()*2-1);

            System.out.println("x = " + x);

            float precise = (float) Math.acos(x);
            float approx  = FastMath.acos(x);

            System.out.println("precise = " + precise);
            System.out.println("approx = " + approx);

            float error = Math.abs(precise-approx);

            assertTrue(error < FastMath.getPrecision());
        }
    }

    public void testSinSpeed(){
        int num = 10000;

        StopWatch libraryTimer = new StopWatch();
        StopWatch fastMathTimer = new StopWatch();



        float [] input = new float[num];
        float [] preciseResults = new float[num];
        float [] approxResults = new float[num];


        for(float precision=10; precision > .000001; precision*=.1f){

            FastMath.setPrecision(precision);
           
            for(int i=0;i<num;i++){
                input[i] = (float) (Math.random()*Math.PI*2);
            }

            libraryTimer.reset();
            libraryTimer.start();
            for(int i=0;i<num;i++){
                preciseResults[i] = (float)Math.sin(input[i]);
            }
            libraryTimer.stop();
            fastMathTimer.reset();
            fastMathTimer.start();
            for(int i=0;i<num;i++){
                approxResults[i] = FastMath.sin(input[i]);
            }
            fastMathTimer.stop();
            //check results
           for(int i=0;i<num;i++){
                float error = Math.abs(preciseResults[i]-approxResults[i]);
                assertTrue(error < FastMath.getPrecision());
            }

            System.out.println("precision = " + FastMath.getPrecision());
            System.out.println("average time for API.sin is " + libraryTimer.time()/(float)num);
            System.out.println("av time for FastMath.sin is " + fastMathTimer.time()/(float)num);
        }

    }

    public void testCosSpeed(){
        int num = 10000;

        StopWatch libraryTimer = new StopWatch();
        StopWatch fastMathTimer = new StopWatch();



        float [] input = new float[num];
        float [] preciseResults = new float[num];
        float [] approxResults = new float[num];


        for(float precision=10; precision > .000001; precision*=.1f){

            FastMath.setPrecision(precision);

            for(int i=0;i<num;i++){
                input[i] = (float) (Math.random()*Math.PI*2);
            }

            libraryTimer.reset();
            libraryTimer.start();
            for(int i=0;i<num;i++){
                preciseResults[i] = (float)Math.cos(input[i]);
            }
            libraryTimer.stop();
            fastMathTimer.reset();
            fastMathTimer.start();
            for(int i=0;i<num;i++){
                approxResults[i] = FastMath.cos(input[i]);
            }
            fastMathTimer.stop();
            //check results
           for(int i=0;i<num;i++){
                float error = Math.abs(preciseResults[i]-approxResults[i]);
                assertTrue(error < FastMath.getPrecision());
            }

            System.out.println("precision = " + FastMath.getPrecision());
            System.out.println("average time for API.cos is " + libraryTimer.time()/(float)num);
            System.out.println("av time for FastMath.cos is " + fastMathTimer.time()/(float)num);
        }

    }

    public void testACosSpeed(){
        int num = 1000000;

        StopWatch libraryTimer = new StopWatch();
        StopWatch fastMathTimer = new StopWatch();

        float [] input = new float[num];
        float [] preciseResults = new float[num];
        float [] approxResults = new float[num];


        for(float precision=10; precision > .00001; precision*=.1f){

            FastMath.setPrecision(precision);

            for(int i=0;i<num;i++){
                input[i] = (float) (Math.random()*2-1);
            }

            libraryTimer.reset();
            libraryTimer.start();
            for(int i=0;i<num;i++){
                preciseResults[i] = (float)Math.acos(input[i]);
            }
            libraryTimer.stop();
            fastMathTimer.reset();
            fastMathTimer.start();
            for(int i=0;i<num;i++){
                approxResults[i] = FastMath.acos(input[i]);
            }
            fastMathTimer.stop();
            //check results
           for(int i=0;i<num;i++){
                float error = Math.abs(preciseResults[i]-approxResults[i]);
                assertTrue("error="+error,error < FastMath.getPrecision());
            }

            System.out.println("precision = " + FastMath.getPrecision());
            System.out.println("average time for API.acos is " + libraryTimer.time()/(float)num);
            System.out.println("av time for FastMath.acos is " + fastMathTimer.time()/(float)num);
        }

    }
}


Tom

Runesketch: an Online CCG built on Google App Engine where players draw their cards and trade. Fight, draw or trade yourself to success.
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline t_larkworthy

Senior Member


Medals: 1
Projects: 1


Google App Engine Rocks!


« Reply #10 - Posted 2007-04-15 00:08:17 »

1  
[code]Actually I managed to speed it up a reasnable amount by getting rid of the sign bit with some loop unrolling

public static float atan(float x){
        //http://en.wikipedia.org/wiki/Arctangent#Infinite_series
        //atan(x) = x - x^3/3 + x^5/5
        float pow=x;
        int n=1;
        //int sign=1;
        float term=x;
        float termABS=Math.abs(term);
        float val =term;

        while(termABS > precision){
            //go up two each time
            n+=2;
            pow*=x*x;
            //sign = sign==1?-1:1;//flip sign every time

            float oldTermABS = termABS;
            //calc next term
            if(n<MAX_EXPANSIONS)
                term=/*sign*/pow*recip[n];
            else
                term=/*sign*/pow/n;

            termABS = Math.abs(term);

            if(oldTermABS<termABS){
                //precision is worsening!
                //caused by pow getting very large, and
                //factorial getting very small
                break;//stop now, things are getting worse!
            }
            val -= term;

            //go up two each time
            n+=2;
            pow*=x*x;
            //sign = sign==1?-1:1;//flip sign every time

            oldTermABS = termABS;
            //calc next term
            if(n<MAX_EXPANSIONS)
                term=/*sign*/pow*recip[n];
            else
                term=/*sign*/pow/n;

            termABS = Math.abs(term);

            if(oldTermABS<termABS){
                //precision is worsening!
                //caused by pow getting very large, and
                //factorial getting very small
                break;//stop now, things are getting worse!
            }
            val += term;
        }
        return val;
    }
[/code]
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
precision = 1.0
average time for API.acos is 1122.7174
av time for FastMath.acos is 155.27678
precision = 0.1
average time for API.acos is 1118.1633
av time for FastMath.acos is 178.82118
precision = 0.010000001
average time for API.acos is 1124.1154
av time for FastMath.acos is 200.12914
precision = 0.0010
average time for API.acos is 1121.4628
av time for FastMath.acos is 227.57458
precision = 1.00000005E-4
average time for API.acos is 1118.9564
av time for FastMath.acos is 241.88194
precision = 1.0000001E-5
average time for API.acos is 1117.9333
av time for FastMath.acos is 263.41922

Runesketch: an Online CCG built on Google App Engine where players draw their cards and trade. Fight, draw or trade yourself to success.
Offline DzzD
« Reply #11 - Posted 2007-04-16 14:09:53 »

NB:

Why did you use float rather than double ?

in most case double are at least as fast as float (usually faster fo me) and give more accurate results , no ? (at least on all computers I done my bench AMD 2000XP+(1.6GHz)  and pentium4 (2Ghz).

and yes.... I know....sorry.... I dont know about the reference of the arytmetic coprocessor for both commputers above.....

Offline t_larkworthy

Senior Member


Medals: 1
Projects: 1


Google App Engine Rocks!


« Reply #12 - Posted 2007-04-17 21:04:48 »

Yeah....floats....Um, JOODE was built using floats in the beginning so it all is now  Undecided. Whether that actually helps anything I am not sure. I naively thought it would be faster when I started. Maybe it saves a bit of space, but the really memory is not a problem with JOODE, speed is the main issue (not a huge issue though). A quick "find an replace" can convert JOODE over to doubles, but I would really prefer a better way (say user selectable, or even self optimizable). I need something like a preprocessor but with IDE support.

Runesketch: an Online CCG built on Google App Engine where players draw their cards and trade. Fight, draw or trade yourself to success.
Offline DzzD
« Reply #13 - Posted 2007-04-17 23:24:02 »

....A quick "find an replace" can convert JOODE over to doubles, but I would really prefer a better way (say user selectable, or even self optimizable). I need something like a preprocessor but with IDE support.

3DzzD API have a bit less than one undred of classes and one day with a lot of motivation.... I done the find and replace method (I only keep float for local object vertex to keep a bit more memory)... it is a long process (could be a cupple of hours) as it introduce some bugs and bottleneck, for exemple casting a double to a int when the double is higher than Integer.MAX_VALUE or is smaller than -Integer.MAX_VALUE cost a lot of time... so when you know that it can append it is a good way to do if(double<2147483647.0 && double>-2147483647) int=(double)double else ..... in an other hands some bugs due to lack of precision was self corrected by using double rather than float....

making both available is certainly the best way but I really dont know how you can achieve this  Roll Eyes

EDIT: NB: float-> double==fast double=>float == slow. to resume : higher precision to lower precision is slow, and, lower precision to higher presion is fast

Offline mabraham

Junior Member





« Reply #14 - Posted 2007-04-21 15:24:42 »

I can't be bothered to profile but I'll wager to say that...

sign = sign==1?-1:1; //flip sign every time
this saves you an if which are damn expensive
sign *= -1; //flip sign every time

...modern CPUs should easily branch-predict this one...

and if you 'inline' the contents of Math.abs(), you will get very likely a significant speedup too

...calls to Math.abs() ought to be auto-inlined by the JVM provided your code runs often enough...
Offline t_larkworthy

Senior Member


Medals: 1
Projects: 1


Google App Engine Rocks!


« Reply #15 - Posted 2007-04-22 12:56:37 »

Yeah, I actually managed to get rid of all the abs calls in exchange for an if at the beggining of the method call. I will leave off posting it becuase it provides only a marginal performance gain.

Runesketch: an Online CCG built on Google App Engine where players draw their cards and trade. Fight, draw or trade yourself to success.
Offline DzzD
« Reply #16 - Posted 2007-11-08 19:02:18 »

This is an update of first version, needed If you plan to use it with Micrososft JVM.

Micrososft JVM will give wrong result with the first version (dont ask me why...), this version is less precise but faster...

NB: Results in comments are given for the high precision version, not this one, but anyways it is still very precise...

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
64  
65  
66  
67  
68  
69  
70  
71  
72  
73  
74  
75  
76  
77  
78  
79  
80  
81  
82  
83  
84  
85  
86  
87  
88  
89  
90  
91  
92  
93  
94  
95  
96  
97  
98  
99  
100  
101  
102  
103  
104  
105  
106  
107  
108  
109  
110  
111  
112  
package net.dzzd.utils;

/**
 *  MathX class.
 *  <br>
 * Base class used by 3DzzD Web 3D Engine to include faster and/or smarter maths functions<br>
 * <br>
 * <u>Some results comparaison between Math.cos and MathX.cos function, MathX.cos seems to be 0.5 to 20 times faster than Math.cos function and give more accurate results especially for PI/2</u><br>
  *<br>
 * <B>-PI</B><br>
 * MathX.cos(-Math.PI) =-1.0<br>
 * Math.cos(-Math.PI)  =-1.0<br>
 *<br>
 * <B>PI</B><br>
 * MathX.cos(Math.PI) =-1.0<br>
 * Math.cos(Math.PI)  =-1.0<br>
 *<br>
 * Root(2)/2=0.7071067811865476<br>
 * <B>PI/4</B><br>
 * MathX.cos(Math.PI*0.25) =0.7071067811865476<br>
 * Math.cos(Math.PI*0.25)  =0.7071067811865476<br>
 *<br>
 * <B>PI/2</B><br>
 * MathX.cos(Math.PI*0.5) =0.0<br>
 * Math.cos(Math.PI*0.5)  =6.123233995736766E-17<br>
 *<br>
 * <B>-PI/4</B><br>
 * MathX.cos(-Math.PI*0.25)=0.7071067811865476<br>
 * Math.cos(-Math.PI*0.25) =0.7071067811865476<br>
 *<br>
 * <B>-PI/2</B><br>
 * MathX.cos(-Math.PI*0.5) =0.0<br>
 * Math.cos(-Math.PI*0.5)  =6.123233995736766E-17<br>
 *<br>
 *  @author Bruno Augier (DzzD)
 *  @version 1.0, 01/03/07
 *  @since 1.0
 * @see IRender3D
 * @see IMesh3D
 * @see DzzD
 * @see <a href="http://dzzd.net/">http://dzzd.net/</a>
 */


public class MathX
{
   public static double PI=Math.PI;

   private static double f2=-0.5;
   private static double f4=-f2/(3.0*4.0);
   private static double f6=-f4/(5.0*6.0);
   private static double f8=-f6/(7.0*8.0);
   private static double f10=-f8/(9.0*10.0);
   private static double f12=-f10/(11.0*12.0);
   private static double f14=-f12/(13.0*14.0);
   private static double f16=-f14/(15.0*16.0);
   //MORE PRECISE BUT NOT COMPATIBLE JVM MS =>//private static double f18=-f16/(17.0*18.0);
  //MORE PRECISE BUT NOT COMPATIBLE JVM MS =>//private static double f20=-f18/(19.0*20.0);
  private static double PI2=2.0*PI;
   private static double PI05=0.5*PI;
   

   /**
   * Compute and return sinus of its parameter using taylor serie
   * @param x angle in radian to
   * @return sinus value for the given parameter
   */

   public static double sin(double x)
   {
      //return Math.sin(x);
     return cos(x-PI05);
   }

   /**
   * Compute and return cosinus of its parameter using taylor serie
   * @param x angle in radian to
   * @return cosinus value for the given parameter
   */
 
    public static double cos(double x)
    {
       
       
       if(x<0.0) x=-x;
       
       
       if(x<PI2)
       {
          if(x<PI)
          {  
            double x2=x*x;
            return 1.0+x2*(f2+x2*(f4+x2*(f6+x2*(f8+x2*(f10+x2*(f12+x2*(f14+x2*(f16))))))));
            //MORE PRECISE BUT NOT COMPATIBLE JVM MS => return 1.0+x2*(f2+x2*(f4+x2*(f6+x2*(f8+x2*(f10+x2*(f12+x2*(f14+x2*(f16+x2*(f18+x2*f20)))))))));      
        }
         else
         {
            x-=PI;
            double x2=x*x;
            return -(1.0+x2*(f2+x2*(f4+x2*(f6+x2*(f8+x2*(f10+x2*(f12+x2*(f14+x2*(f16)))))))));
            //MORE PRECISE BUT NOT COMPATIBLE JVM MS => return -(1.0+x2*(f2+x2*(f4+x2*(f6+x2*(f8+x2*(f10+x2*(f12+x2*(f14+x2*(f16+x2*(f18+x2*f20))))))))));      
        }
       }
       
       
       x%=PI2;
       x-=PI;
      double x2=x*x;
     
      return -(1.0+x2*(f2+x2*(f4+x2*(f6+x2*(f8+x2*(f10+x2*(f12+x2*(f14+x2*f16))))))));
      //MORE PRECISE BUT NOT COMPATIBLE JVM MS => return -(1.0+x2*(f2+x2*(f4+x2*(f6+x2*(f8+x2*(f10+x2*(f12+x2*(f14+x2*(f16+x2*(f18+x2*f20))))))))));
     
   }  
     
}

Pages: [1]
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

CogWheelz (18 views)
2014-07-30 21:08:39

Riven (26 views)
2014-07-29 18:09:19

Riven (15 views)
2014-07-29 18:08:52

Dwinin (13 views)
2014-07-29 10:59:34

E.R. Fleming (34 views)
2014-07-29 03:07:13

E.R. Fleming (12 views)
2014-07-29 03:06:25

pw (44 views)
2014-07-24 01:59:36

Riven (44 views)
2014-07-23 21:16:32

Riven (30 views)
2014-07-23 21:07:15

Riven (31 views)
2014-07-23 20:56:16
List of Learning Resources
by SilverTiger
2014-07-31 18:29:50

List of Learning Resources
by SilverTiger
2014-07-31 18:26:06

List of Learning Resources
by SilverTiger
2014-07-31 13:54:12

HotSpot Options
by dleskov
2014-07-08 03:59:08

Java and Game Development Tutorials
by SwordsMiner
2014-06-14 00:58:24

Java and Game Development Tutorials
by SwordsMiner
2014-06-14 00:47:22

How do I start Java Game Development?
by ra4king
2014-05-17 11:13:37

HotSpot Options
by Roquen
2014-05-15 09:59:54
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!