# Sin() and Cos() equivalent

Discussion in 'C' started by manava, Jun 20, 2008.

1. ### manavaNew Member

Joined:
Jun 20, 2008
Messages:
1
0
Trophy Points:
0
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,multcos,multsin;
{
//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,

2. ### xpi0t0sMentor

Joined:
Aug 6, 2004
Messages:
3,009
203
Trophy Points:
63
Occupation:
Senior Support Engineer
Location:
England
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)%.