Calculating sin(x), cos(x), and exp (x)

As the title says I'm trying to create a program that calculates all three of these results and displays them compared to Library result. I've manages to get sin(x) working but have had no luck getting cos(x) and exp(x) to work.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include <iostream>
#include <iomanip>
#include <cmath>

using namespace std;

int main()
{
    char more = 'Y';
    double x, mySin(double);

    do{
        cout << "\n\t\tInput X: ";
        cin >> x;
        cout << "\n\t\t\t\tLibraryResult\tMyResult";
        cout << "\n\tsin(" << x << ")"<< setw(10) << "\t" << setprecision(6) << fixed << mySin(x) << "\t" << sin(x); //<---- Not working "mySin" not declared
       // cout << "\n\tcos(" << x << ")\t"<< "PLACEHOLDER" << "\t" << "PLACEHOLDER";
       // cout << "\n\texp(" << x << ")\t"<< "PLACEHOLDER" << "\t" << "PLACEHOLDER";

        cout << "\n\t\tDo more (Y/N) ? ";
        cin >> more;
   } while ( more == 'y' || more == 'Y');
}
double mySin(double x)
{
    double sum, power(double, int), fact(int);
    int    i, sign;

    for (i=0, sign=1, sum=0.; i<21; i++, sign = -sign)
        sum=sum + sign * power (x, 2 * i + 1) / fact(2 * i + 1);

    return sum;
}
double fact(int n)
{
    int i;
    double prod = 1.;
    for (i = 1; i <= n; i++)
        prod = prod * i;

    return prod;

}
double power (double x, int n)
{

    int i;
    double prod = 1;
    for (i + 0; i < n; i++)
        prod = prod * x;
    return prod;
}



[edit] I just noticed that my result for sin(x) isnt right and now i have no idea what i need to change...
Last edited on
Your Maclaurin series approximation is only close to sin(x) near 0.

Fortunately, sin(x) is periodic, so this makes things easier. Reduce x modulo 2pi so that it is near to zero and work from there.

You might accomplish this by saying x = -(std::fmod(x, pi * 2) - pi); before substituting x into the polynomial (line 28).

Note also that sin(x + pi/2) = cos(x).

By the way, it generally doesn't make any sense to place function prototypes at local scope. This is because each local declaration must be modified when the function signature changes. Further, if the declaration is mismatched, it won't even be possible to detect the error until link time. Further, the local declaration will only find names in the current namespace, won't instantiate templates, and will fill otherwise short functions with boilerplate.

It's best to declare every function (that needs a separate declaration) just once near the top of the file.
Last edited on
@caymwin,
You have seen a mathematical statement of the series for sin(x) and tried to code exactly to that, working out powers and factorials from scratch for each separate term. Apart from potential overflow, this is hugely inefficient, as each power contains within its factors all previous powers, and each factorial contains within its factors any previous factorial. Thus, each term is a simple multiple of the previous term.

In particular, you don't have to (indeed, shouldn't) calculate factorials and powers from scratch each time.

Also, why stop at a particular value of i? This may truncate the series before the terms get sufficiently small. You need a loop-termination criterion based on the (absolute) size of the term.

Here is a simple version of sin(x) that will do away with the need for procedures power() and factorial() completely. Can you spot similar rules for cos() and exp()?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
double mySin( double x )
{
   const double TOLERANCE = 1.0e-10;
   double term = x;
   double result = term;

   for ( int i = 1;  abs( term ) > TOLERANCE; i += 2 )
   {
      term *= -x * x / ( ( i + 1 ) * ( i + 2 ) );
      result += term;
   }

   return result;
}


Using periodicity properties, bringing x into a smaller range (such as -pi to +pi) as @mbozzi has suggested will also make convergence much more rapid when the absolute value of x is large, at least for sin() and cos().
Last edited on
cos is just sin shifted. use your sin function and add a constant offset for cos.
@lastchance I appreciate your response. The goal of this program was to be able to calculate all 3 answers without the use of power(x,n) and fact(n). I should have definitely included this in the main post. The code that I provided is what my instructor gave us as a jump start for calculating sin(x). I know the code probably looks very sloppy and non optimal but that's where I ended up after an hour or trial and error...
The goal of this program was to be able to calculate all 3 answers without the use of power(x,n) and fact(n)

Do you mean with the use of power & fact? Otherwise your first post doesn't make much sense to me. If you meant without, then what is wrong with lastchance's post?
Last edited on
You don't initialize i in your power function:

1
2
3
4
5
6
7
8
double power (double x, int n)
{
    int i;                     // nothing here
    double prod = 1;
    for (i + 0; i < n; i++)    // pointless initialization statement
        prod = prod * x;
    return prod;
}

Normally we would write that something like:

1
2
3
4
5
6
7
double power (double x, int n)
{
    double prod = 1;
    for (int i = 0; i < n; i++)
        prod *= x;
    return prod;
}

only need integer powers? Or do you want fractional powers?
you can do fractional powers with logs I think, or if that is cheating, a bit more code.

an amusing version of integer only powers. It is every so slightly faster than the loop for large powers (higher than 10 or so)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
 double ipowf(double p, unsigned long long e) 
{ 
  const double one = 1.0;
  const double *lut[2] = {&p,&one};
  double result = 1.0;
  result *= lut[!(e&1)][0]; p *= p;
	result *= lut[!(e&2)][0]; p *= p;
	result *= lut[!(e&4)][0]; p *= p;
	result *= lut[!(e&8)][0]; p *= p;
	result *= lut[!(e&16)][0]; p *= p;
	result *= lut[!(e&32)][0]; p *= p;
	result *= lut[!(e&64)][0]; 
	return result;
}
Last edited on
Thank you all so much for the help!
Topic archived. No new replies allowed.