Subversion Repositories programming

Rev

Rev 173 | Blame | Compare with Previous | Last modification | View Log | RSS feed

/* Copyright: Ira W. Snyder
 * Start Date: 2005-11-28
 * End Date: 2005-11-29
 * License: Public Domain
 *
 * Changelog Follows:
 * 2005-11-28
 * - Implement eval_euler() and eval_trapezoid().
 *
 * 2005-11-29
 * - Implement eval_romberg() and eval_simpson().
 * - eval_trapezoid() was giving horrible results, fix it.
 *
 */

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

/**
 * The function given in the Project #5 Handout.
 * This is 1 + x^28
 *
 * @param x the point at which to evaluate the function
 */
float func (float x)
{
    return 1.0 + pow (x, 28);
}

/**
 * Evaluate the integral of the function given, over the interval given,
 * using the Euler method.
 *
 * @param a the lower bound of the integral
 * @param b the upper bound of the integral
 * @param n the number of intervals to use
 * @param f the function to evaluate
 */
float eval_euler (const float a, const float b, const int n, float(*f)(float))
{
    const float h = (b - a) / n;
    float answer = 0.0, xi = 0.0;
    int i = 0;

    for (i=0; i<=n; i++)
    {
        xi = a + (i * h);
        answer += f(xi);
    }

    return h * answer;
}

/**
 * Evaluate the integral of the function given, over the interval given,
 * using the trapezoid method.
 *
 * This is derived from the book's pseudocode on Pg 207.
 *
 * @param a the lower bound of the integral
 * @param b the upper bound of the integral
 * @param n the number of intervals to use
 * @param f the function to evaluate
 */
float eval_trapezoid (const float a, const float b, const int n, float(*f)(float))
{
    const float h = (b - a) / n;
    float sum = 0.0;
    int i = 0;

    sum = (1.0/2.0) * (f(a) + f(b));

    for (i=1; i<=n-1; i++)
        sum += f(a + (i * h));

    return h * sum;
}

/**
 * Evaluate the integral of the function given, over the interval given,
 * using the Romberg method.
 *
 * This is directly based on the pseudocode on Pg 223-224 of the textbook.
 *
 * @param a the lower bound of the integral
 * @param b the upper bound of the integral
 * @param n the number of intervals to use
 * @param f the function to evaluate
 */
float eval_romberg (const float a, const float b, const int n, float(*f)(float))
{
    float R[n+1][n+1];
    int i, j, k;
    float h, sum;

    /* Check for values that make us run wild, and refuse to run */
    if (n > 25)
    {
        printf ("Cowardly refusing to run... You shouldn't need to use a\n"
                "value of n > 25. Remember, the inner loop runs (2^n) - 1.\n");
        return 0.0;
    }

    h = b - a;
    R[0][0] = (h/2.0) * (f(a) + f(b));

    for (i=1; i<=n; i++)
    {
        h = h/2.0;
        sum = 0.0;

        for (k=1; k<=(pow(2.0, i) - 1); k+=2)
            sum = sum + f(a + k * h);

        R[i][0] = (1.0/2.0) * R[i-1][0] + sum * h;

        for (j=1; j<=i; j++)
            R[i][j] = R[i][j-1] + (R[i][j-1] - R[i-1][j-1]) / (pow(4.0, j) - 1);
    }

    return R[n][n];
}

/**
 * Evaluate the integral of the function given, over the interval given,
 * using the Simpson method.
 *
 * This is derived from the formula on Pg 237-238
 *
 * @param a the lower bound of the integral
 * @param b the upper bound of the integral
 * @param n the number of intervals to use
 * @param f the function to evaluate
 */
float eval_simpson (const float a, const float b, const int n, float(*f)(float))
{
    const float h = (b - a) / n;
    float sum1=0.0, sum2=0.0;
    int i;

    /* Get the first sum in the formula on Pg 238 */
    for (i=1, sum1=0.0; i<=n/2; i++)
        sum1 += f (a + (2 * i - 1) * h);

    sum1 *= 4;

    /* Get the second sum in the formula on Pg 238 */
    for (i=1, sum2=0.0; i<=(n-2)/2; i++)
        sum2 += f (a + 2 * i * h);

    sum2 *= 2;

    /* Add it all together, and return it */
    return (h / 3.0) * ((f(a) + f(b)) + sum1 + sum2);
}

int main (void)
{
    const float a = 0.0;
    const float b = 3.0;
    const float real = 3.0 + (pow(3.0, 29.0) / 29.0);
    float h, comp, abs, rel;
    int i, n;

    /* Euler Method Header */
    printf ("Euler's Method\n");
    printf ("i       h               Computed        Abs Error       Rel Error\n");
    printf ("====================================================================\n");

    /* Euler Method Table */
    for (i=1; i<=25; i++)
    {
        h = pow(2.0, -i);
        n = (int)((b - a) / h);
        comp = eval_euler (a, b, n, &func);
        abs = fabs(real - comp);
        rel = fabs(real - comp) / fabs(real);

        printf ("%.2d\t%e\t%e\t%e\t%e\n", i, h, comp, abs, rel);
    }

    /* Trapezoid Method Header */
    printf ("\n\nTrapezoid Method\n");
    printf ("i       h               Computed        Abs Error       Rel Error\n");
    printf ("====================================================================\n");

    /* Trapezoid Method Table */
    for (i=1; i<=25; i++)
    {
        h = pow(2.0, -i);
        n = (int)((b - a) / h);
        comp = eval_trapezoid (a, b, n, &func);
        abs = fabs(real - comp);
        rel = fabs(real - comp) / fabs(real);

        printf ("%.2d\t%e\t%e\t%e\t%e\n", i, h, comp, abs, rel);
    }

    /* Romberg Method Header */
    printf ("\n\nRomberg's Method\n");
    printf ("i       h               Computed        Abs Error       Rel Error\n");
    printf ("====================================================================\n");

    /* Romberg Method Table
     *
     * NOTE: Don't go higher than 3 for this one, since the Romberg method's inner
     *       loop runs (2^24) - 1 = 16777216 times at i=3 and
     *       (2^48) - 1 = 2.81474 * 10^14 times at i = 4.
     */
    for (i=1; i<=3; i++)
    {
        h = pow(2.0, -i);
        n = (int)((b - a) / h);
        comp = eval_romberg (a, b, n, &func);
        abs = fabs(real - comp);
        rel = fabs(real - comp) / fabs(real);

        printf ("%.2d\t%e\t%e\t%e\t%e\n", i, h, comp, abs, rel);
    }

    /* Simpson Method Header */
    printf ("\n\nSimpson's Method\n");
    printf ("i       h               Computed        Abs Error       Rel Error\n");
    printf ("====================================================================\n");

    /* Simpson Method Table */
    for (i=1; i<=25; i++)
    {
        h = pow(2.0, -i);
        n = (int)((b - a) / h);
        comp = eval_simpson (a, b, n, &func);
        abs = fabs(real - comp);
        rel = fabs(real - comp) / fabs(real);

        printf ("%.2d\t%e\t%e\t%e\t%e\n", i, h, comp, abs, rel);
    }

    return 0;
}