Search code examples
ctrigonometrytaylor-series

Cosine Taylor approximation C language


I'm working at something easy...I guess, but there is something that bothers me.

double x,t,cos_aprox,eps;
int k;
t=1.0;
k=1;
cos_aprox=1.0;`

printf("Introduceti x pentru care se calculeaza cos(x) si eroarea epsilon:\n");
if(scanf("%lf%lf",&x,&eps)!=2)
{
    printf("Date eronate!!\n");
    exit(1);
}
else
{
    do
    {
        t=t*(-1)*x*x/(k*(k+1));
        cos_aprox+=t;
        k+=2;
    }
    while(fabs(t)>eps);

    printf("Valoarea aproximativa a lui cos(%g) este %.9g. k este %d\n",x,cos_aprox,k);
    printf("Valoarea lui cos(%g), folosind functia din biblioteca, este %.9g.",x,cos(x));
}

It returns good results but when I choose any value over 39 radians there is a significant difference between it and library function cos(x).


Solution

  • OP's use of the Taylor's series suffers from numerical limitations with increasing values of x. The addition of large alternating sign terms accumulate too much error. Amend code to see these terms.

    t = t*(-1)*x*x/(k*(k+1));
    printf("%e\n", t);
    

    Both sine and cosine calculation benefit with argument reduction to a range of [-2π ... +2π]. The following is a good 1st step and will provide reduce the error for x over wider range.

    x = fmod(x, 2*π);
    

    Further reduction to the range [0 ... +π/4] can be employed using the usual trigonometric identities and remquo(). Degrees example


    The trouble is that the above calculation relies on an approximate value of π. π, being an irrational number, cannot be represented exactly as a double. All finite double are rational numbers. So instead machine pi is used.

    // example
    #define M_PI 3.1415926535897932384626433832795
    x = fmod(x, M_PI);
    

    To achieve accurate calculations over the entire range of double x requires sophisticated extended precision techniques. Search for Argument reduction for huge arguments: Good to the last bit