# Fast Cosine Approximation

This topic is 2852 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

Hey guys,

I'm trying to remove what seems to be a bottle neck in my noise function. I have a call to Math.Cos() which calculates the cosine in double precision but also adds another function call and cast to float. I have seen simple methods of estimating the cosine function in the past (using a parabola I think) but I'm having trouble tracking them down.

Anyways, here is the function I wish to speed up, any help is appreciated:

// cosine interpolation between a and b by a factor of x
public float lerp(float a, float b, float x)
{
float ft = x * 3.1415927f;
float f = (1.0f - (float)Math.Cos(ft)) * 0.5f;
return a * (1.0f - f) + b * f;
}

##### Share on other sites
In the range -pi/2 to pi/2 you can use the approximatoion
cos(x) ~ -(x-pi/2)(x+pi/2)/(pi*pi/4)

(This approximation is different from the Taylor expansion 1-x^2/2+... but has the nice property of having roots at exactly -pi/2 and pi/2)

##### Share on other sites
Thanks! I may end up using that.

Also I managed to dig up the article I was looking for: http://www.devmaster.net/forums/showthread.php?t=5784

Is there any way to remove the abs()? I am working with the compact .net framework which does not inline any function calls. Calling Math.Abs() may make it pointless.

float sine(float x){    const float B = 4/pi;    const float C = -4/(pi*pi);    float y = B * x + C * x * abs(x);    #ifdef EXTRA_PRECISION    //  const float Q = 0.775;        const float P = 0.225;        y = P * (y * abs(y) - y) + y;   // Q * y + P * y * abs(y)    #endif}

##### Share on other sites
This file has several approximations for trigonometric functions. The
header has the restrictions on the domain of these functions.

##### Share on other sites
If you are working with 32 bit floats all the time, you may want to try changing the precision and rounding mode at the start of the application:

_controlfp(_PC_24, _MCW_PC)_controlfp(_RC_NEAR, _MCW_RC)

Every now and then you will have to check a DLL (i.e. Direct3D) didn't change it back:
assert( (_controlfp(0, 0) & _MCW_PC) == _PC_24 );assert( (_controlfp(0, 0) & _MCW_RC) == _RC_NEAR );

By the way, what happens when you just use cosf()?

If precision isn't your concern, try changing your compiler optimizations from Precise to Fast (in MSVC, Alt+F7 -> C++ -> Code Generation -> Floating Point Model)

Cheers
Dark Sylinc

Edit: Oh I see, this seems C#, then you're probably f**ked.

##### Share on other sites
Yeah, I'm stuck with c#. Which is why I do not want to use the Math.Cos class. It's overkill for what I need.

I guess I am going to use this:
        public static float Cos(float x)        {            const float B = 4 / PI;            const float C = -4 / (TwoPi);            x -= PIby2;            return -(B * x + C * x * ((x < 0) ? -x : x));        }        public static float CosLerp(float a, float b, float x)        {            const float B = 4 / PI;            const float C = -4 / (TwoPi);            float ft = x * PI;            //float f = (1.0f - (float)Math.Cos(ft)) * 0.5f;            float c = ft - PIby2;            float f = (1.0f + (B * c + C * c * ((c < 0) ? -c : c))) * 0.5f;            return a * (1.0f - f) + b * f;        }

edit: even without the extra precision this will do nicely

[Edited by - arriu on September 27, 2010 5:30:08 PM]

1. 1
Rutin
25
2. 2
3. 3
4. 4
JoeJ
17
5. 5

• 14
• 14
• 11
• 9
• 9
• ### Forum Statistics

• Total Topics
631757
• Total Posts
3002123
×