Go4Expert

Go4Expert (http://www.go4expert.com/)
-   C (http://www.go4expert.com/forums/c/)
-   -   Sin() and Cos() equivalent (http://www.go4expert.com/forums/sin-cos-equivalent-t11520/)

manava 21Jun2008 01:53

Sin() and Cos() equivalent
 
Hello,
I am using sin() and cos() built in functions in my C++ code. However after profiling it I realized that the 2 functions consume a lot of time. So I decided to eliminate sin() and cos() functions and replace it with an equivalent code that generates the same values for me, using either trigonometric identities or something else (Please suggest!). I tried an approach, which is shown below, but I am not getting the required results due to errors in it (The problem I assume is because of the large number of loops it goes through -- 35000*35000 which marginally moves it away from the desired result). Can somebody help me with this or another approach which might be more precise and correct. I have not shown the entire code because its big and unwanted. I just want a replacement for sin() and cos().

Code:


// This is the code that works correctly but consumes a lot of time
main()
float phase=0.0, rate=2.5e6, raw[35000],multcos[35000],multsin[35000];
{
//some statements here

for(int i=0;i<35000;i++)
{
//some statements here

for(int j=0;j<35000;j++)
{
arg=(2*3.14*fc*j)/rate  + phase;
multcos[j]=raw[j]*cos(arg); //I want to replace this cos()
multsin[j]=raw[j]*sin(arg);  //I want to replace this sin()
//raw[j] has some predefined values

Sum1[H[j]]=Sum1[H[j]] + multcos[j];
Sum2[H[j]]=Sum2[H[j]] + multsin[j];
//H[j] has some predefined values;
//Sum1[] has been initilized to 0;

}
//some statements here
}

//some statements here
}//end of main


Below is the replacement/equivalent code I wrote to replace sin and cos functions.


Code:

//This is the equivalent code that does not work correctly

float G_cb, G_b=1.57071406,        G_a=0.0;
        float G_snm2,        G_snm1,        G_cnm2, G_cnm1;
        float G_s,G_c;

for(i=0;i<35000;i++)
{
        G_cb = 2* cos(G_b * PI/180);
        G_snm2 = sin(G_a + G_b);  G_snm1 = sin(G_a + 2*G_b);
        G_cnm2 = cos(G_a + G_b);  G_cnm1 = cos(G_a + 2*G_b);

        for(int j=0;j<35000;j++)
    {
        G_s = (G_cb * G_snm1) - G_snm2 ;
        G_c = (G_cb * G_cnm1) - G_cnm2 ;
        G_snm2 = G_snm1;  G_cnm2 = G_cnm1;
        G_snm1 = G_s;  G_cnm1 = G_c;

        multcos[j]= raw[j] * G_c;
        multsin[j]= raw[j] * G_s;
       
      Sum1[H[j]]=Sum1[H[j]] + multcos[j];
      Sum2[H[j]]=Sum2[H[j]] + multsin[j];
      //H[j] has some predefined values;
      //Sum1[] has been initilized to 0;

    }
}

Please help me.
Thanks,
prads

xpi0t0s 17Jul2008 16:19

Re: Sin() and Cos() equivalent
 
One approach is to determine the maximum error you're prepared to live with, then replace the sin() function with a series of straight line segments; specify fixed values at fixed points then for intermediate points use linear interpolation. You can eliminate three quarters of the data you would otherwise need for a full sinewave by using symmetry; define values for 0-90 degrees then e.g. sin(180+x)=-sin(x); sin(-x)=-sin(x) etc.

e.g.1: a simple straight line from (0,0) to (90,1). sin(45)=0.7071, but our approximation is 0.5, which is a huge error of .2071. But this will be really fast and could in certain circumstances be acceptable (for example if we're generating a 10kHz sound wave and will be chucking the output through a 20kHz low pass filter such as a human ear).
e.g.2: two straight lines from (0,0) to (.5,.7071) to (90,1). sin(22.5)=0.3827 but our approximation is 0.3536 (off by .0291). This is considerably better for a lookup table of only 2 values (because we can include the endpoints in the code)
e.g.3: three straight lines from (0,0) to (30,.5) to (60,.8660) to (90,1). sin(15)=0.2588 and our approximation is 0.25 (off by 0.0088 which is less than 5%).

You can use the same lookup table for cos because cos(x)=sin(x+90).
The symmetry of cos around x=0 (cos(-x)=cos(x)) might make it better to define the values for cos then sin(x)=cos(x-90).

Also you can avoid compounding errors by leaving the calculation until as late as possible. If you have, say, a 20-step calculation where sin() is called at step 1 and each step adds a possible x% error, then the error present in the sin replacement is compounded by (20^(1+)x)% (I think, anyway, it's x% compounded 20 times; use same calculation as compound interest). However if the sin function can be left until later, say until step 10, then the error is only compounded (10^(1+)x)%.


All times are GMT +5.5. The time now is 11:08.