#include "integrate.h"
#include <math.h>
#include <stdio.h>

typedef struct
{
    float a2, a1, a0;
} quad_t;

static float f_quad(float x, void *ctx)
{
    const quad_t *q = (const quad_t *)ctx;
    return (q->a2 * x * x) + (q->a1 * x) + q->a0;
}

static void run_one(const char *name, integrand_f f, void *ctx, float a,
                    float b, float exact, unsigned n)
{
    float r = 0.0f, t = 0.0f, s = 0.0f;
    integ_status_t stS;

    midpoint(f, ctx, a, b, n, &r);
    trapezoid(f, ctx, a, b, n, &t);

    stS = simpson(f, ctx, a, b, n, &s);

    printf("\n%s on [%.6f, %.6f], n=%u\n", name, a, b, n);
    printf("Exact:      %.9f\n", exact);
    printf("Midpoint:   %.9f  err=%.9f\n", r, fabsf(r - exact));
    printf("Trapezoid:  %.9f  err=%.9f\n", t, fabsf(t - exact));
    if (stS == INTEG_OK)
        printf("Simpson:    %.9f  err=%.9f\n", s, fabsf(s - exact));
    else
        printf("Simpson:    not computed (n must be even)\n");
}

int main(void)
{
    const quad_t q = {1.0f, 0.0f, 0.0f}; /*x^2*/

    const quad_t q2 = {-1.0f, 3.0f, 50.0f}; /*x^2+3x+50*/

    const quad_t q3 = {-9.0f, 3.0f, -100.0f}; /*-9x^2+3x-100*/

    const quad_t q4 = {6.0f, -10.0f, 0.0f}; /*6x^2-10x*/

    run_one("x^2", f_quad, (void *)&q, 0.0f, 1.0f, 1.0f / 3.0f, 10u);

    run_one("x^2+3x+50", f_quad, (void *)&q2, -3.0f, 15.0f, 90.0f, 22u);

    run_one("-9x^2+3x-100", f_quad, (void *)&q3, 12.0f, 15.0f, -5119.5f, 2u);

    run_one("6x^2-10x", f_quad, (void *)&q4, -50.0f, -5.0f, 262125.0f, 6u);

    return 0;
}
