Search code examples
c++taylor-series

Getting inf in a Taylor expansion for e^x, but only for small error bounds


I am writing a program to approximate an exponential function, but I'm running into a problem. For small values of err the program messes up and just loops forever, getting approximations of inf every time. The program seems to be intolerant of larger and larger errors as larger x's are entered. It works fine for, say, x=1 and err=10e-5. As an example of when it doesn't work: x=3 it works fine up to err=10e-4 but when err=10e-5 it results in inf.

//This program approximates e^x at a given x to a given accuracy
#include<algorithm>
#include<cmath>
#include<iostream>
#include<string>
#include<vector>
using namespace std;
inline void keep_window_open() {char ch; cin >> ch;}
class bad_entry{};
int fac(int a) //function to find factorial
{
    int f=1; //covers 0!
    for(int w=0; w<a; ++w)
    {
        f*=(a-w);
    }
    return f;
}
int main()
{
    try
    {
        double x=0;
        double ans=0;
        double err=0;
        int n=0; 
        cout << "What number do you want to expand around?\n";
        cin >> x;
        if(!cin){throw bad_entry{};}
        cout << "What would you like the error to be within?\n";
        cin >> err;
        if(!cin){throw bad_entry{};}
        double actual=exp(x);
        while(n>=0)
        {
            ans += pow(x,n)/fac(n);
            cout << "n=" << n << '\t' << "Approx: " << ans << '\t' << "Erro: " << abs(actual-ans) << '\n';
            if(abs(actual-ans)<err)
            {
                keep_window_open();
                return 0;
            }
            ++n;
        }
    }
    catch(bad_entry)
    {
        cout << "\nINVALID ENTRY\n";
        return 0;
    }
}

Solution

  • If you write a program that just prints fac for increasing n values, you'll get:

    n=1  fac=1
    n=2  fac=2
    n=3  fac=6
    n=4  fac=24
    n=5  fac=120
    n=6  fac=720
    n=7  fac=5040
    n=8  fac=40320
    n=9  fac=362880
    n=10 fac=3628800
    n=11 fac=39916800
    n=12 fac=479001600
    n=13 fac=1932053504  // Ups - wrong - should be 6227020800
    n=14 fac=1278945280  // Ups - wrong
    n=15 fac=2004310016  // Ups - wrong
    

    So you have an overflow already for n equal 13. Therefore all calculations will fail and give strange results.

    If you change fac function to use uint64_t instead of int it will be a little better, i.e. higher n before overflow.