2
$\begingroup$

This is a problem that my friend has. He says he has to create a C++ program to evaluate the series (He says we must use functions):

$\displaystyle\large\sin x\approx x- \frac{x^3}{3! }+\frac{x^5}{5!}-\frac{x^7}{7!}\cdots\pm\frac{x^n}{n!}$

The values of $x$ and $n$ have to be taken from the user.

Only I'm not good with C++. Can anyone help?

  • 0
    Voted to close. This forum is already full of math homework, we don't need computer homework as well!2012-08-19

4 Answers 4

5

As $T_n=\frac{x^{2n+1}}{(2n+1)!}$ and $T_1=x$

So, $T_{n-1}=\frac{x^{2n-1}}{(2n-1)!}$

So, $T_n=T_{n-1}\frac{x^2}{(2n+1)2n}$

I have utilized this so that we don't need to calculate the powers of x and the factorial every time.

I've assumed that the number of terms is not required as by repeated division, y will eventually be reduced 0 due to the limited precision of double datatype.

Also, x is to be measured in radian(not in degree), as prescribed by the Taylor Series.

      void main(int argc, char **argv)       {           double x , sinx, y;           printf("enter x:\n");           scanf("%lf",&x);            sinx=y=x;           int sign = -1;          for (int idx = 1;; idx++) {              y = y * (x / (2 * idx)) * (x/(2 * idx - 1));              if (y == 0)                 break;              sinx = sinx + sign * y;              sign = -sign;          }          printf("\n\nsin(%lf) = %lf", x, sinx);       } 
  • 0
    Also, since OP asked for C++ code it might be more appropriate to use `std::cin >> x` and `std::cout << (...) << std::endl;` for input and output operations2012-08-19
3

If you are looking for speed, don't recompute the factorials or powers.

// Assumes n > 0 double sin(double x, int n) {     const double x_squared = x*x;     int term_num = 1;     double sum = 0.0;     double current_power_of_x = x;     double current_factorial = 1.0;     double sign = 1.0;     while(term_num <= n) {         sum += sign * current_power_of_x / current_factorial;         current_power_of_x *= x_squared;         current_factorial *= (term_num + 2.0) * (term_num + 1.0);         sign *= -1.0;         term_num += 2.0;     }      return sum; } 
  • 0
    (I have never heard of "Horner scheme" before, though you are correct that the wiki page describes what I am doing). I would just call it "caching partial results" which is commonplace for programmers.2012-08-19
3

Too long for a comment:

The recurrence method in lab bhattacharjee's or nullUser's answers should be preferred over Jack's as it avoids computing expensive factorial terms repeatedly. Some more tweaks would significantly improve this program.

As is, the program will output rubbish for any input of $|x|>10.$ The series will be adding and subtracting very large numbers whose decimal digits are truncated, and you'll most likely not even output a value between -1 and 1. We want smaller values of $x$ so that this doesn't happen and the series converges more quickly. Thus the first tweak would be to use the periodicity/symmetry properties of the sine function to reduce the computation of $\sin x$ to the computation of $\sin x_0$ where $x_0$ is some value between $0$ and $\pi/2.$

Another trick is to exploit the identity $\sin (x_0) = 2 \sin (x_0/2) \sqrt{1- \sin^2 (x_0/2)}$ - applying it twice, we need only compute the series with an input between 0 and $\pi/8<0.4.$ In this range, the series converges very quickly; even with $n=2$ the maximum error in the series computation is $ 0.4^7/7! \approx 3 \cdot 10^{-7}.$ With $n=3$ the maximum error is $0.4^9/9! \approx 7 \cdot 10^{-10}.$

  • 0
    @labbhattacharjee I've given the descriptions above, the reason I haven't given the code for them is because I have no idea how to program in C or Java. And because of that, I'm not sure how your code or java.lang.Math.sin(double) works either.2012-08-19
2

If your friend's function evaluates it to a certain number of terms, this should work:

double sin(double x, int terms) {     if(terms == 1)         return x;     double result = 0;     for(int j = 1; j <= terms; j++) {         if (j % 2 == 1)             result += pow(x, j * 2 - 1) / factorial(j * 2 - 1);         else             result -= pow(x, j * 2 - 1) / factorial(j * 2 - 1);     }     return result; }  long factorial(int num) {     long result = 1;     for(int j = num; j > 1; j--)         result *= j;     return result; } 

Sorry if this looks funny--posting from my iPhone.

  • 0
    Watch out for numerical problems for large x. The terms will first grow and then get small, and the alternating sum will cause problems. You can ensure x is from [-pi, pi] by something like x -= 2*pi*int(x/(2*pi)). Also, seeing that definition of factorial makes me cringe. Start with fact = 1 and then do fact *= 2*j*(2*j+1).2012-08-19