noobprogger February 2016

How do I end this while loop with a precision of 0.00001 ([C++],[Taylor Series])?

I'm working on this program that approximates a taylor series function. I have to approximate it so that the taylor series function stops approximating the sin function with a precision of .00001. In other words,the absolute value of the last approximation minus the current approximation equals less than or equal to 0.00001. It also approximates each angle from 0 to 360 degrees in 15 degree increments. My logic seems to be correct, but I cannot figure out why i am getting garbage values. Any help is appreciated!

#include <math.h>
#include <iomanip>
#include <iostream>
#include <string>
#include <stdlib.h>
#include <cmath>
double fact(int x){
   int F = 1;
    for(int i = 1; i <= x; i++){
        F*=i;
    }
    return F;
   }
double degreesToRadians(double angle_in_degrees){
  double rad = (angle_in_degrees*M_PI)/180;
  return rad;
 }
 using namespace std;
double mySine(double x){
   int current =99999;
   double comSin=x;
   double prev=0;
   int counter1 = 3;
   int counter2 = 1;
   while(current>0.00001){
    prev = comSin;
    if((counter2 % 2) == 0){
      comSin += (pow(x,(counter1))/(fact(counter1)));
    }else{
      comSin -= (pow(x,(counter1))/(fact(counter1)));
    }
   current=abs(prev-comSin);
   cout<<current<<endl;
   counter1+=2;
   counter2+=1;
   }
   return comSin;
}

using namespace std;
int main(){
cout<<"Angle\tSine"<<endl;
 for (int i = 0; i<=360; i+=15){
 cout<<i<<"\t"<<mySine(degreesToRadians(i));
 }




 }

Answers


Christopher Oicles February 2016

Here is an example which illustrates how to go about doing this. Using the pow function and calculating the factorial at each iteration is very inefficient -- these can often be maintained as running values which are updated alongside the sum during each iteration.

In this case, each iteration's addend is the product of two factors: a power of x and a (reciprocal) factorial. To get from one iteration's power factor to the next iteration's, just multiply by x*x. To get from one iteration's factorial factor to the next iteration's, just multiply by ((2*n+1) + 1) * ((2*n+1) + 2), before incrementing n (the iteration number).

And because these two factors are updated multiplicatively, they do not need to exist as separate running values, they can exists as a single running product. This also helps avoid precision problems -- both the power factor and the factorial can become large very quickly, but the ratio of their values goes to zero relatively gradually and is well-behaved as a running value.

So this example maintains these running values, updated at each iteration:

  • "sum" (of course)
  • "prod", the ratio: pow(x, 2n+1) / factorial 2n+1
  • "tnp1", the value of 2*n+1 (used in the factorial update)

The running update value, "prod" is negated every iteration in order to to factor in the (-1)^n.

I also included the function "XlatedSine". When x is too far away from zero, the sum requires more iterations for an accurate result, which takes longer to run and also can require more precision than our floating-point values can provide. When the magnitude of x goes beyond PI, "XlatedSine" finds another x, close to zero, with an equivalent value for sin(x), then uses this shifted x in a call to MaclaurinSine.

#include <iostream>
#include <iomanip>

// Importing cmath seemed wrong LOL, so define Abs and PI
static double Abs(double x) { return x < 0 ? -x : x; }
const do 

Post Status

Asked in February 2016
Viewed 3,419 times
Voted 13
Answered 1 times

Search




Leave an answer