We're a community of 1077K IT Pros here for help, advice, solutions, professional growth and fun. Join us!
1,076,085 Members — Technology Publication meets Social Media
Username:
Password:
Lost login information?
Start New Discussion Reply to this Discussion

Trigonometric Function Optimization

I have the following trig functions, but I am wondering if there is a faster algorithm that I could implement:

static const double SINMIN=0.0009999998333333;
    static const double COSMIN=0.9999995000000417;
    static const double TANMIN=0.0010000003333334;
    static const double E=2.718281828459045235360;
    static const double PI=3.14159265358979323846;
    static const double MINVAL=0.01;
    double sin(double ax)
{
    double x=aabs(ax);
    if (x==MINVAL)
    {
        switch (quadrant(ax))
        {
            case 1:
            case 2:
            return SINMIN;
            case 3:
            case 4:
            return -SINMIN;
        }
    }
    else
        return (SINMIN*cos(x-MINVAL)+COSMIN*sin(x-MINVAL));
}
    double cos(double x)
{
    if (x==MINVAL)
    {
        switch (quadrant(ax))
        {
            case 1:
            case 4:
            return COSMIN;
            case 2:
            case 3:
            return -COSMIN;
        }
    }
    else
        return (COSMIN*cos(x-MINVAL)+SINMIN*sin(x-MINVAL));
}
    double tan(double x)
{
    if (x==MINVAL)
    {
        switch (quadrant(ax))
        {
            case 1:
            case 3:
            return TANMIN;
            case 2:
            case 4:
            return -TANMIN;
        }
    }
    else
        return ((TANMIN+tan(x-MINVAL))/(1.0000000000000-(TANMIN*tan(x-MINVAL))));
}
4
Contributors
4
Replies
9 Hours
Discussion Span
2 Years Ago
Last Updated
5
Views
Question
Answered
Labdabeta
Practically a Master Poster
615 posts since Feb 2011
Reputation Points: 27
Solved Threads: 31
Skill Endorsements: 1

Sure.
If you insist on recursive approach, it is better to half the argument, rather than subtract a small decrement. For example, to calculate sin(0.5), your code goes down 50 levels of recursion, while halfing does only 6. Another speedup is achieved by sincos, which calculates both sin and cos simultaneously, and performs faster than any of them:

sincos(double x, double * sin, double * cos)
{
    if(fabs(x) < epsilon) {
        *sin = x;
        *cos = 1.0 - x*x/2.0;
        return;
    }
    double s, c;
    sincos(x/2, &s, &c);
    *sin = 2.0*s*c;
    *cos = c*c - s*s;
}

As a side note, in the base case for sin and tan you should return x instead of SIN/TANMIN (for cos it is 1 - x*x/2).

nezachem
Posting Shark
913 posts since Dec 2009
Reputation Points: 719
Solved Threads: 197
Skill Endorsements: 0

First of all, if(x==MINVAL) makes no sense, I think you meant to write if(x < MINVAL) .

Second, I'm pretty certain that you would be better off using a Tailor series expansion. All you should need is a Taylor series expansion around 0 degrees for both the sine and cosine, which is valid (within you desired precision) on an interval from -45 degree to 45 degrees (i.e. -Pi/4 to Pi/4). With simple trig. identities, you should be able to use those two expansions to calculate a sine, cosine or tangent of any angle. For example, for the sine of an angle of 80 degrees, you can compute the cosine of -10 degrees (which is in the Taylor series' range for the cosine), and similarly for other ranges of values.

Third, you should also remember that branchings (e.g. conditional statements) are surprisingly expensive and slow, you should reduce those to a minimum. Also, mark your free-functions with the keyword "inline" to allow the compiler to inline if it leads to faster code.

Finally, if you are using or can use C++0x, you should mark those functions with constexpr keyword to allow compile-time computation of the values whenever possible.

mike_2000_17
21st Century Viking
Moderator
3,136 posts since Jul 2010
Reputation Points: 2,050
Solved Threads: 625
Skill Endorsements: 41

Thanks, those ideas helped a lot!

Labdabeta
Practically a Master Poster
615 posts since Feb 2011
Reputation Points: 27
Solved Threads: 31
Skill Endorsements: 1
Question Answered as of 2 Years Ago by mike_2000_17 and nezachem

First of all, if(x==MINVAL) makes no sense, I think you meant to write if(x < MINVAL) .

Second, I'm pretty certain that you would be better off using a Tailor series expansion. All you should need is a Taylor series expansion around 0 degrees for both the sine and cosine, which is valid (within you desired precision) on an interval from -45 degree to 45 degrees (i.e. -Pi/4 to Pi/4). With simple trig. identities, you should be able to use those two expansions to calculate a sine, cosine or tangent of any angle. For example, for the sine of an angle of 80 degrees, you can compute the cosine of -10 degrees (which is in the Taylor series' range for the cosine), and similarly for other ranges of values.

Third, you should also remember that branchings (e.g. conditional statements) are surprisingly expensive and slow, you should reduce those to a minimum. Also, mark your free-functions with the keyword "inline" to allow the compiler to inline if it leads to faster code.

Finally, if you are using or can use C++0x, you should mark those functions with constexpr keyword to allow compile-time computation of the values whenever possible.

I would suspect using trig function be just as fast if not faster than taylor expansion.

@OP: Unless you are in a really limited environment, there is no need for all this complication. You should just use a simple one liner function call.

firstPerson
Industrious Poster
4,044 posts since Dec 2008
Reputation Points: 851
Solved Threads: 625
Skill Endorsements: 15

This question has already been solved: Start a new discussion instead

Post: Markdown Syntax: Formatting Help
 
You
View similar articles that have also been tagged:
 
© 2013 DaniWeb® LLC
Page rendered in 0.0813 seconds using 2.88MB