-1

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).

Cœur
  • 37,241
  • 25
  • 195
  • 267
  • 2
    Works only if the argument is in the range `[-pi/4,pi/4]`. You'll need big integer math for the amount of digits of pi you need for the reduction. paper: http://citeseer.ist.psu.edu/viewdoc/summary?doi=10.1.1.67.5616 – deamentiaemundi Jan 21 '17 at 20:27
  • Use `x = fmod(x, 2*pi);` before the while loop for improvement. This will still have trouble for large `x` like `x > 1e10`. The details of how to work `cos()` precisely over a wide range using your own code are not "something easy" – chux - Reinstate Monica Jan 21 '17 at 23:02

1 Answers1

1

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

Community
  • 1
  • 1
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256