-1

I am trying to code Taylor series but I am getting 'nan' as output in case of large value of n(=100). Where am I doing things wrong?

#include<iostream>
#include<cmath>
using namespace std;

 int main(){

    int n;
    double x;

    cin >> n;
    cin >> x;

    long double temp_val = 1;
    int sign = 1;
    int power = 1;
    long long int factorial = 1;


    for(int i = 1 ; i < n ; i++){

        sign = sign* -1 ;
        power =  2*i;
        factorial  = factorial*(2*i)*(2*i-1);

        temp_val += sign*pow(x,power)/factorial;
    }
    cout<<temp_val;

}
walnut
  • 21,629
  • 4
  • 23
  • 59
Ashish M
  • 119
  • 8
  • 3
    `power` looks like it could quickly overflow. – François Andrieux Feb 19 '20 at 22:32
  • @FrançoisAndrieux any idea, how to resolve? – Ashish M Feb 19 '20 at 22:37
  • 1
    look at the actual values going into the function call that gave NaN. It can help if you split the expression up into multiple separate lines so you can see the intermediate steps. – JDługosz Feb 19 '20 at 22:37
  • 1
    If `double` doesn't have the needed range, look at https://www.boost.org/doc/libs/1_71_0/libs/multiprecision/doc/html/index.html – JDługosz Feb 19 '20 at 22:40
  • 1
    Please don't fix the problem that you are asking about in the question. It makes the question and answers nonsensical for future readers. I have reverted your edit. – walnut Feb 19 '20 at 22:58

2 Answers2

5

For large n your program has undefined behavior.

You are calculating the factorial of 2n (so 200) in factorial. 200! is, according to Wolfram Alpha:

788657867364790503552363213932185062295135977687173263294742533244359449963403342920304284011984623904177212138919638830257642790242637105061926624952829931113462857270763317237396988943922445621451664240254033291864131227428294853277524242407573903240321257405579568660226031904170324062351700858796178922222789623703897374720000000000000000000000000000000000000000000000000

For comparison, the typical largest value that a long long int can hold is

9223372036854775807

(which is assuming it is 64-bit)

Clearly you will not be able to fit 200! into that. When you overflow a signed integer variable your program will have undefined behavior. That means that there will be no guarantee how it will behave.

But even if you change the variable type to be unsigned, not much will change. The program won't have undefined behavior anymore, but the factorial will not actually hold the correct value. Instead it will keep wrapping around back to zero.

Even if you change factorial to be type double, this will probably not be enough with at typical double implementation to hold this value. Your platform might have a long double type that is larger than double and able to hold this value.

You will have similar problems with pow(x, power) if x is not close to 1.

As mentioned in the answer by @idclev463035818 the Taylor series, if evaluated straightforwardly, is numerically very ill-behaved and can not really be used practically in this form for large n.

walnut
  • 21,629
  • 4
  • 23
  • 59
3

Calculating the taylor series has a trap that also occurs in other situations: Both the numerator and denominator of the terms to add grow rather fast and overflow easily, but their quotient converges to zero (otherwise adding them up till infinity would not converge to a finite number).

Instead of keeping track of both terms individually you need to update the result and the total increment. I wont provide you a full solution. In pseudo-code

double res = 0;
double delta = x;
int n = 1;
double sign = -1;
while ( ! stop_condition ) {
    delta *= (x / n);
    res += sign*delta;
    ++n;
    sign *= -1;
}
463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185