cosinus function

Started by
25 comments, last by Jesper T 22 years, 5 months ago
Im not sure which forum this should go in blah blah, but here it is.. I made a function that calculates the cosine to an angle:
                

// definitions:


#define ONEPI  3.14159265358 // 97932384626433832795  
  

#define TWOPI  6.28318530717 // 95864769252867665590  // didnt need ALL those decimals lol    


#define PRES 25	    // Presicion, 25 makes it as presice as the cmath cos function 


// didnt gain so much speed by decreasing it (strange..)



// function:

double Cos( double ang )
{
  bool    cyc = true;
  int     u = 2;
  double  vrb[3];

  if( ang >  TWOPI ) { while( ang >  TWOPI ) { ang -= TWOPI; }}
  if( ang < -TWOPI ) { while( ang < -TWOPI ) { ang += TWOPI; }}

  vrb[2] = 1;

  while( u <= PRES )
  {
    vrb[0] = 1;
    vrb[1] = 1;

    for(int k = 1; k <= u; k++)
    {
      vrb[0] *= k;	// vrb[0] = u!

      vrb[1] *= ang;	// vrb[1] = ang^u

    }
    
    if(cyc)	
    {
      vrb[2] -= vrb[1] / vrb[0];
    }
    else 
    {
      vrb[2] += vrb[1] / vrb[0];
    }

    cyc = !cyc;
    u += 2;
    }
  return vrb[2];
}

    
What u think of it ? Can anyone think of a way to make it faster (without making it too inacurate)? Now it is about 99% the speed of the cmath cos function, but since this thing is placed directly into the source file it should be possible to make it faster.. right ? Edit: trying to make it readable.. Edited by - Jesper T on November 2, 2001 4:17:39 AM
Advertisement
Some ideas:

* restrict the range more, e.g. to 0 to pi/2. The smaller the angle the quicker the power series will converge. Then use the properties of cosine, such as cos(-a) == cos(a), to derive the cosine for angles outside this range from this.
* the initial two lines to limit the range will take a long time with large input angles. If this is a problem consider using mod.
* precalculate the factorials instead of calculating them each time. Store them as 1/factorial to eliminate the need for the diviison. You can also store them as alternate + or -, eliminating the need for ''cyc'' to keep track of whether at odd or even term (though this makes them less useful generally).
* as well as a fixed number of iterations also test for the terms getting small enough. E.g exit the loop if ang^n/n! is less than some limit of accuracy.
* Use seperate floats instead of an array for the locals, as this will let the compiler allocate them to registers (though this is compiler/platform dependent).
* if you can get the number of iterations down consider unrolling the loop (again how much this helps is compiler/processor dependent).
* finally consider doing it another way: if speed is important a method using lookup and interpolation can be a lot faster, at a cost of extra storage for the lookup tables.
GCC''s cosine function is much much faster than yours. Besides that, take out those clamp loops (they slow it down a lot). Just make sure that the user passes clamped data. Here''s an idea. Instead of your loops, try:
  #define FOURPI 12.5663706143// ...while( ang > TWOPI ) { ang -= FOURPI; }while( ang < -TWOPI ) { ang += TWOPI; }  

That sped it up a lot in my tests (I was using a big number though). You probably don''t need those if''s, also. Anyway, my advise is still to use the built in cosine function .

[Resist Windows XP''s Invasive Production Activation Technology!]
ok, thanks for the tips

I tried this:

     #define  HLFPI  1.57079632679 #define  ONEPI  3.14159265358 #define  TWOPI  6.28318530717  double FACS[7] = { -0.5000000000000,                    0.0416666666667,                   -0.0013888888889,                    0.0000248015873,                   -0.0000002755731,                    0.0000000020876,                   -0.0000000000014 };  // function:double Cos( double ang ){   bool    n = false;    double  t;    double  r = 1;    int     e = 2;    if( ang < 0.0 )   { ang = -ang; }   while( ang >  TWOPI ) { ang -= TWOPI; }   if( ang > ONEPI ) { ang = TWOPI - ang; }   if( ang > HLFPI ) { ang = ONEPI - ang; n = true; }   for(int f = 0; f < 6; f++)    {      t = ang;       for(int k = 1; k < e; k++)       {         t *= ang;        }      r += t * FACS[f];        e += 2;     }   if(n){ return -r; }    else { return  r; } }    


By restricting the angle to: PI/2 > angle > 0 I only need to run the loop six times.. its seems _slightly_ faster, but I think that my system is a bit too unstable to do acurate tests on (lots of strange programs running in the background I think hehe)
Well I'll probably use the built in cosinus/sinus functions anyway, but its fun trying to do make ur own versions aswell

edit: eye cat'n toype corrctly

Edited by - Jesper T on November 2, 2001 5:50:21 AM

"GCC''s cosine function"

whats GCC ?
.. actually, I get correct values even if I only run the loop 5 times.. strangely I didnt notice any speed change.. hmmm


quote:Original post by Jesper T

"GCC''s cosine function"

whats GCC ?


GCC = "GNU Compiler Collection". Its a freeware compiler for multiple computer platforms, from the Free Software Foundation. It supports various languages including C, C++, Fortran, and others. You can easily write cross-platform console apps using GCC, and on free OS''s such as Linux you can access windowing libraries, OpenGL, etc. But it may not have good support (if any) for Windows application development, using Windows OpenGL, DirectX, or the Windows graphical interface though.

Check out: http://www.gnu.org/software/gcc/gcc.html

Oh, an "GNU" means "Gnu''s Not Unix"

Someone else probably can fill in some blanks on this.



Graham Rhodes
Senior Scientist
Applied Research Associates, Inc.
Graham Rhodes Moderator, Math & Physics forum @ gamedev.net
edit: /me posts two times just to be sure

Edited by - Jesper T on November 2, 2001 2:14:47 PM
hmm ok, thanks.




(I want to guive yuo teh impresion that I am very intelgient)
quote:Original post by grhodes_at_work
But it may not have good support (if any) for Windows application development, using Windows OpenGL, DirectX, or the Windows graphical interface though.

The GCC compiler works fine for Windows development if you have a port of the Win32 libraries to GCC. Most people use the MinGW32 port, with Dev C++ as their IDE .

[Resist Windows XP''s Invasive Production Activation Technology!]

This topic is closed to new replies.

Advertisement