Sin() and Cos() equivalent

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

  1. manava

    manava New Member

    Joined:
    Jun 20, 2008
    Messages:
    1
    Likes Received:
    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[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
     
  2. xpi0t0s

    xpi0t0s Mentor

    Joined:
    Aug 6, 2004
    Messages:
    3,009
    Likes Received:
    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)%.
     

Share This Page

  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice