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;     } }```
Thanks,

 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 22:56.