Search code examples
clogicapproximationtaylor-series

Taylor Series logic in C


I am working on the project where we are approximating e^x using a taylor series, with x being a user entered value. The test values that we have been given are x=.5, x=1.0, and x=1.5. The goal is to get the output is supposed to be a table with a row for each iteration of the loop that creates the series, with the first column containing the number of iterations, the second column the theoretical value (based on exp(x)), the third the total of the summation, and the forth difference between the theoretical value and the iterated value.

My code as it is currently is below. As it stands, my logic has some hole in it, as the code builds and runs, but the output is not correct. If I were to take a stab at my problem, i think that my summation is not starting in the right spot (1), and that the first two terms are wrong (1+x+(x^2/2!)+(x^3/3!)... etc).

What logic should I be using vs what I have? Thanks.

//cs 1325
// Dean Davis
// Dr. Paulk
// series convergence homework.

#include <stdio.h>
#include <float.h> // need it for FLT_EPSILON
#include <math.h>


unsigned long factorial(int); // function will calculate the factorial 

int main()
{
    int n = 0;
    unsigned long fact;  // this variable will hold the factorial value
    float x; // this will be the value read in from the user
    double theoval; // this will hold the theoretical value of e^x
    double holder; // will hold the value of the nth term
    double total = 0; // will accumulate the total summation
    double diff;  // will hold the sifferential between theoretical value and the summation
    puts("Please enter a numerical value greater than zero: "); // request input
    scanf_s("%f", &x); // read it in
    theoval=exp(x); // calc the theoretical value

    printf("# Iter      e^x       Sum       Diff\n");
    printf("-------   -------     -------   -------\n"); // set up the output

    while ((theoval - total) >= FLT_EPSILON) //the loop to continue to sum the summation
    {
        fact = factorial(n); // calls the factorial function
        holder = (pow(x, n)) / fact; // calculates the term n
        total = total + holder;  // adds to the sum
        diff = theoval - total;  // calc the diff
        printf(" %-9d%-12.6f%-14.6f%-10.8f\n", n, theoval, total, diff); // output it
        if ((theoval - total) >= FLT_EPSILON) // if it is smaller, then we don't wan't to increment n
            continue;
        else
            n++;
    }

    printf("The number of iterations required for convergence is: %d\n", n); // out put this line

}


unsigned long factorial(int n)
{
    unsigned long int fact=n; 
    if (n == 0) // if n is zero, 0!=1
        return 1;
    else // so long as it is not, then we can calculate it like this
    {
        n--; // decrement it
        for (n; n > 0; n--)
        {
            fact = fact*n; // multiply the next number by the product of all the preceding terms
        }
        return fact;
    }
}

Solution

  • Your main problem is here:

        if ((theoval - total) >= FLT_EPSILON) // if it is smaller, then we don't wan't to increment n
            continue;
        else
            n++;
    

    The logic is both backwards and unnecessary. It's backwards because you avoid incrementing n in exactly those cases where you want to increment it, and it's unnecessary because in the other cases you're about to exit the loop anyway because the while expression is false. Just increment n unconditionally.

    This expression is also a little suspect:

    (theoval - total) >= FLT_EPSILON
    

    The macro FLT_EPSILON is related to the spacing between representable float values near 1.0. The spacing is different in different places, so it does not make sense to use it as an absolute error bound. Since the Taylor series has a well defined error bound in the form of the remainder term, I suggest instead computing the maximum possible value of the remainder term for the current n, and exiting if the ratio of that bounding error value value to the current sum is less than some reasonably small value, such as maybe 0.00001.