0

I'm trying to compute the value of cos x using the Taylor series formula

             infinity
             ----                  2k
             \            k      x
 cos(x) =    /        (-1)  * -------------
             ----                (2k)!
             k=0

Shown graphically at http://ppt.cc/G,DC

Here is my program.

#include "stdafx.h"
#include <iostream>
#include <string>
#include <cmath>
using namespace std;


int _tmain(int argc, _TCHAR* argv[])
{
    double sum=0.0,sum1=0.0;
 double x;
 cin>>x;
 for(int i=0 ; i<=10 ; i=i+1 )
 {
  for(int i=1 ; i<=20 ; i=i+1)
  {
   sum1=i*sum1+sum1;
  }
     sum=pow(-1,(double)i)*pow(x,(double)(2*i))/sum1+sum;
 }
 cout<<"Sum : "<<sum<<endl;
 system("pause");
 return 0;
}

The output is -1.#IND

Why?

How can I change the order of "sum1" to make it work right?

Ken Bloom
  • 57,498
  • 14
  • 111
  • 168
Max
  • 1
  • 1
  • You want us to download stuff first to find out what exactly is the problem you're trying to solve? And do you really need all that Windows-y stuff for homework? Can you show us your output? Please be more descriptive. – wkl Dec 15 '10 at 03:02
  • Why are you casting an int to a double? What do you mean strange words? what words? Why would that print words? – Falmarri Dec 15 '10 at 03:02
  • Long ago, when I wrote it for an 8bit ucontroller, I've used precomputed values for Taylor coefficients.. – ruslik Dec 15 '10 at 03:14
  • It even gives you warnings. Don't ignore warnings. – Falmarri Dec 15 '10 at 04:07

5 Answers5

2

You're using i as the name of the controlling variables for two for-loops that are nested inside each other. That won't work the way you expect.

Next, sum1 is 0. No matter how many times you multiply zero by things and add zero to it, it's still zero. Then you divide by zero, which is why your final answer is NaN (not-a-number).

You need to fix the computation of factorial. Why don't you write a factorial function and test it by itself first?

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • @Max: It's zero because you set it to zero as the very first line of your program (`double sum1 = 0.0;`). Then, you add zero to it a bunch of times, so it's still zero. – Ben Voigt Dec 15 '10 at 04:01
1

You're redeclaring i inside your inner loop.

for(int i=0 ; i<=10 ; i=i+1 )
 {
  for(int i=1 ; i<=20 ; i=i+1)

It's been a while since I've done C, but I'm fairly sure that's an error.

Falmarri
  • 47,727
  • 41
  • 151
  • 191
  • 2
    No, it's not. The inside one hides the outside one. It IS a **very bad idea**, but not a compile error. – Ben Voigt Dec 15 '10 at 03:07
  • @Max: I doubt it does what you've expected. You've just used to write `for (int i= ...` for any loop. And it's bad because you are not notified with error, so it's you who should be careful. – ruslik Dec 15 '10 at 03:27
  • @Falmarri: And the strangest thing is that this actually works correctly on my gcc!! `int rez = 0; for (int i = 0; i< 10; i++) for (int i = 0; i< 10; i++) rez++;` actually returns 100! – ruslik Dec 15 '10 at 03:33
  • @Ben: Sorry, I didn't mean a compile error. I meant a general error, as in bug. – Falmarri Dec 15 '10 at 04:05
1

Many things are a bit weird. First : Please write ANSI C++ and try not to adopt the Microsoft Stuff, I don't really know but I guess those are for the pro's. Lets just stick to the basic stuff. Here is what you should do :

#include <iostream>
#include <string>
#include <cmath>

using namespace std;

double factorial(double fac)
{
    if(fac == 0)
        return 1;
    return fac * factorial(fac - 1);
}

int main(int argc, char* argv[])
{
    double sum=0.0;
    double x;
    cin >> x;

    for ( int i = 0 ; i <= 10 ; i++ )
    {
        double divisor = factorial ( 2 * i );
        if(divisor != 0.0)
        {
            sum += (double)( (pow( -1 , i ) * pow (x , 2*i )) / divisor );
        }
    }
    cout<<"Sum : "<<sum<<endl;
    //system("pause");
    return 0;
}

You are not only calculating the Factorial in a weird way, but you also dont use the math operators correctly and you dont perform the math calculation as you would like to. Also the code you wrote is very weird that way because it does not make it clear (not even for you from what I understand). Look at what others commented too. They are right.

  • #include "stdafx.h" as well... Forgot to add it. Otherwise from what I remember Mr. MSVC will not compile –  Dec 15 '10 at 03:24
  • it's been a long time since I used MSVC, but all of the stuff in this program is ANSI standard, so it should compile without `stdafx.h` – Ken Bloom Dec 15 '10 at 03:30
  • @Ken: It depends on compiler options. If options are set to "precompile header stdafx.h", it will throw a fit if it can't find it. – Ben Voigt Dec 15 '10 at 04:02
1

When you divide by 0, the result becomes infinity (which prints out as -1.#IND)

Muggen has given a good naive way of doing this, recomputing the whole factorial each time, and using the pow function to compute the alternating sign in the formula. But there are improvements that you can make to this code faster.

  1. The Factorial function in one iteration of the loop can take advantage of the fact that you already multiplied most of the terms you need in the prior iterations of the loop.

  2. The exponent (-1)^k is just a way to alternate between addition and subtraction -- you can replace that by having a variable that alternates its sign every iteration through the loop. (There are other ways to do this besides what I showed here, the point is that you don't need to call the pow() function to do it.)

  3. The other power function x^(2k) can also be unrolled the same way.

  4. I eliminated the first iteration of the loop, because I could calculate it in my head (it was 1.0, for any x), and set the initial value of sum to 1.0. This way factorial doesn't ever get multiplied by 0.

Try this instead

#include "stdafx.h"
#include <iostream>
#include <string>
#include <cmath>
using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
 double x;
 cin>>x;
 double sum=1.0, factorial=1.0, sign=-1.0, power=1.0;
 for(int i=1 ; i<=10 ; i=i+1 )
 {
     factorial*= (2*i-1) * 2*i;
     power *= x * x; 
     sum += sign * power/factorial;
     sign = -sign;
 }
 cout<<"Sum : "<<sum<<endl;
 system("pause");
 return 0;
}
Community
  • 1
  • 1
Ken Bloom
  • 57,498
  • 14
  • 111
  • 168
  • factorial*= (2*i-1) * 2*i; at first iteration will become 0. When i==0, 2*0*Whatever == 0 too. –  Dec 15 '10 at 03:30
  • +1 for smart solution, had something like that in my mind too but didn't want to confuse OP. –  Dec 15 '10 at 03:37
  • @Muggen: I was going to give a progression of steps, starting with what turned out to be your answer, followed by the answer that I gave here. When I saw the banner pop up and saw your answer, I stopped *writing* your answer and replaced it with a link. – Ken Bloom Dec 15 '10 at 03:40
  • `pow(x, 2*i)` can also be done iteratively. Hint, first rewrite as `pow(x*x,i)`, then save `x*x` in some helper variable. – Ben Voigt Dec 15 '10 at 04:08
  • @Ben Voigt: Thanks for noticing that. I've edited the answer to include that. (I expect the compiler would optimize out the repeated x*x for me.) – Ken Bloom Dec 15 '10 at 04:24
  • It probably would be somewhat better to write a recurrence relationship for the entire term (`term *= -x * x / (2*i*(2*i-1))`), since the magnitude will be much more stable than the numerator and denominator separately. Finally, because this is an alternating series, once term starts decreasing (i.e. `x*x < 2*i*(2*i-1)`, or roughly `i > x/2`, term becomes an upper limit on the residual error. So it also provides a nice dynamic stopping condition. – Ben Voigt Dec 15 '10 at 04:37
0

It does not appear that you are computing the factorial correctly. should be

sum1 = 1.0;
for(int k=1 ; k<=i*2 ; k=k+1) 
{ 
    sum1 *= k; 
} 

Notice that the factorial terminates a at your outer loop i, and not the fixed number 20, When i is 5, you don't want 20!, you want (2*5)!.

ThomasMcLeod
  • 7,603
  • 4
  • 42
  • 80
  • -1: `sum1 *= 2*k` isn't going to compute a factorial -- it's going to skip half of the numbers that need to be multiplied in this formula. – Ken Bloom Dec 15 '10 at 03:16
  • @Ken: thanks. BTW, this loop calculates the correct factorial when i == 0. – ThomasMcLeod Dec 15 '10 at 03:41
  • `int sum1 = 1.0;`? First, it's gonna overflow. Then, it's gonna go out of scope at the end of the loop without giving you a chance to *use* the result. – Ben Voigt Dec 15 '10 at 04:06
  • @Ben: per Max's original code, both i and sum1 are declared in an outer scope. – ThomasMcLeod Dec 15 '10 at 04:20
  • 1
    And per your code, you're redeclaring a second variable named `sum1` whose scope is limited to the loop, and hides the outer variable for the duration of the loop. Just like Max did with `i`, and rightly got rebuked for doing. – Ben Voigt Dec 15 '10 at 04:22
  • There is still something a little strange here. I believe -1.#IND is usually the result of a mathematical indterminate such as 0/0 or log(-1). Don't we get 1.#INF from 1/0? Leads me to believe the numerator is 0 as well. – ThomasMcLeod Dec 15 '10 at 04:26
  • 1/0 is undefined in the limit. If the denominator approaches zero from above, the answer tends to +infinity. If the denominator approaches zero from below, the answer tends to -infinity. – Ben Voigt Dec 15 '10 at 04:58
  • Agreed. But in IEEE 754 floating point arithmetic, 0/0 and 1/0 are encoded differently. -1.#IND represents 0/0, while 1.#INF represents 1/0. see http://stackoverflow.com/questions/347920/what-does-1-inf00-1-ind00-and-1-ind-means – ThomasMcLeod Dec 15 '10 at 05:23