# Create a C++ program to evaluate the following series: $\sin x \approx x - \frac{x^3}{3! }+\frac{x^5}{5!}-\frac{x^7}{7!}\cdots\pm\frac{x^n}{n!}$ [closed]

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?

-

## closed as off topic by Jennifer Dylan, GEdgar, Chris Eagle, Sasha, Asaf KaragilaAug 19 '12 at 19:44

Questions on Mathematics Stack Exchange are expected to relate to math within the scope defined by the community. Consider editing the question or leaving comments for improvement if you believe the question can be reworded to fit within the scope. Read more about reopening questions here. If this question can be reworded to fit the rules in the help center, please edit the question.

LaTeX tips: Please don't use display style or large in titles. Also, you can have centered equations by enclosing the LaTeX between $$..$$ instead of $..$. –  user2468 Aug 19 '12 at 14:51
I'd suggest changing the series to $x - \frac{x^3}{3!} + \frac{x^5}{5!} - \frac{x^7}{7!}+ \ldots \pm \frac{x^n}{n!}$, to avoid any confusion. –  SiliconCelery Aug 19 '12 at 15:03
Post updated. :) –  David Aug 19 '12 at 15:06
You'd change it to \approx because the series is approximating sin(x), not evaluating it exactly. –  jrad Aug 19 '12 at 15:15
@SiliconCelery I think it would be more appropriate to write $$\displaystyle\large\sin x\approx x- \frac{x^3}{3! }+\frac{x^5}{5!}-\frac{x^7}{7!}+\cdots +(-1)^{n}\frac{x^{2n+1}}{(2n+1)!}$$ –  Argon Aug 19 '12 at 15:40

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);
}

-
For really good performance, one may look into netlib.org/fdlibm/s_sin.c and netlib.org/fdlibm/k_sin.c (by Sun Microsystems), sourceware.org/git/?p=glibc.git;a=blob_plain;f=sysdeps/ieee754/… (by IBM --> this's hardly readable) –  lab bhattacharjee Aug 19 '12 at 16:51
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 operations –  nullUser Aug 19 '12 at 17:47

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;
}

-
Since we're talking C++, some template metaprogramming could speed up the calculation as well. –  You Aug 19 '12 at 16:02
It should be noted that nullUser here is implicitly using the Horner scheme to evaluate the truncated sine series. –  Guess who it is. Aug 19 '12 at 16:11
(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. –  nullUser Aug 19 '12 at 17:43

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}.$

-
could you please share a few of the tricks for better performance. Also, I observed that the value which is calculated by my code significantly differs from that returned by java.lang.Math.sin(double). How do they calculate? –  lab bhattacharjee Aug 19 '12 at 16:40
@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. –  Ragib Zaman Aug 19 '12 at 16:51

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.

-
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). –  marty cohen Aug 19 '12 at 15:37