% Created 2026-01-27 Di 15:23
% Intended LaTeX compiler: pdflatex
\documentclass[11pt]{article}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage{graphicx}
\usepackage{longtable}
\usepackage{wrapfig}
\usepackage{rotating}
\usepackage[normalem]{ulem}
\usepackage{amsmath}
\usepackage{amssymb}
\usepackage{capt-of}
\usepackage{hyperref}
\let\oldsection\section
\renewcommand{\section}{\clearpage\oldsection}
\let\oldsubsection\subsection
\renewcommand{\subsection}{\clearpage\oldsubsection}
\author{Mia Kronner Matr. 22201686}
\date{\today}
\title{Documentation for AutoSW Topic 5: Numerical integration methods}
\hypersetup{
 pdfauthor={Mia Kronner Matr. 22201686},
 pdftitle={Documentation for AutoSW Topic 5: Numerical integration methods},
 pdfkeywords={},
 pdfsubject={},
 pdfcreator={Emacs 30.2 (Org mode 9.7.34)}, 
 pdflang={English}}
\usepackage{calc}
\newlength{\cslhangindent}
\setlength{\cslhangindent}{1.5em}
\newlength{\csllabelsep}
\setlength{\csllabelsep}{0.6em}
\newlength{\csllabelwidth}
\setlength{\csllabelwidth}{0.45em * 3}
\newenvironment{cslbibliography}[2] % 1st arg. is hanging-indent, 2nd entry spacing.
 {% By default, paragraphs are not indented.
  \setlength{\parindent}{0pt}
  % Hanging indent is turned on when first argument is 1.
  \ifodd #1
  \let\oldpar\par
  \def\par{\hangindent=\cslhangindent\oldpar}
  \fi
  % Set entry spacing based on the second argument.
  \setlength{\parskip}{\parskip +  #2\baselineskip}
 }%
 {}
\newcommand{\cslblock}[1]{#1\hfill\break}
\newcommand{\cslleftmargin}[1]{\parbox[t]{\csllabelsep + \csllabelwidth}{#1}}
\newcommand{\cslrightinline}[1]
  {\parbox[t]{\linewidth - \csllabelsep - \csllabelwidth}{#1}\break}
\newcommand{\cslindent}[1]{\hspace{\cslhangindent}#1}
\newcommand{\cslbibitem}[2]
  {\leavevmode\vadjust pre{\hypertarget{citeproc_bib_item_#1}{}}#2}
\makeatletter
\newcommand{\cslcitation}[2]
 {\protect\hyper@linkstart{cite}{citeproc_bib_item_#1}#2\hyper@linkend}
\makeatother\begin{document}

\maketitle
\tableofcontents

\section{Declaration of self reliance}
\label{sec:orga095243}
I hereby declare that I have written this thesis independently in accordance with § 35 para. 7 RaPO (Framework Examination Regulations for Universities of Applied Sciences in Bavaria, BayRS 2210-4-1-4-1-WFK), have not submitted it elsewhere for examination purposes, have not used any sources or aids other than those indicated, and have marked all direct and indirect quotations as such.
\section{Task desciption}
\label{sec:org4a38da4}
Topic 5: Numerical integration methods
The aim of this task is to implement three variants of numerical approaches for calculating integrals
in a software module.
A function for the rectangle method, the trapezoid method, and the Simpson method should be designed and coded in a reusable module.
When defining the interface of the C functions, pay attention to reusability.
The task also includes developing a sample application to test the three variants. Select two examples of mathematical functions whose integrals are to be determined, with corresponding integration boundaries, and compare the three methods in terms of their precision. Test the limitations of the methods. Substantiate your results.
Explain the mathematical relationships underlying the methods in your paper. A graphical representation will help to illustrate the understanding of the relationships.
Optimize the source code as far as possible for performance-optimized use on an embedded controller.
The result of the task is a project that can be compiled with MS Studio, which enables the software module to be tested (suitable test cases, etc.) using a command line application, plus the documentation specified below.
Scope of relevant task-specific documentation
\begin{itemize}
\item Graphical representation of the software design and compact description of the key relationships (1 page)
\item Theoretical explanation of the relationships (mathematical, algorithmic, etc.) that need to be taken into account here (2 pages)
\item Documentation of the reference examples used for testing, with graphical representation and explanation of method limitations (2 pages)
\end{itemize}
\section{Graphical representation of the software design}
\label{sec:org784d853}
\begin{center}
\includegraphics[width=.9\linewidth]{./graphical-representation-white.drawio.png}
\end{center}
\section{Theoretical explanation of the relationships}
\label{sec:org8218260}
\oldsubsection{\texttt{"integrate.h"}:}
\label{sec:orgc92e0ac}
Interface for \texttt{integrate.c} Module.
Here is declared:
\begin{itemize}
\item a void float function pointer for the mathematical function which is to be integrated \texttt{integrand\_f}.
\item a typedef which contains the possible return values for the three integration functions \texttt{integ\_status\_t}
\item the three integration functions \texttt{midpoint} (rectangle midpoint method), \texttt{trapezoid} (trapezoid method), and \texttt{simpson} (simpson 1/3 method)
\begin{itemize}
\item they each take a integrand function \texttt{integrand\_f f}, its context as a void pointer \texttt{void *ctx}, the limits \texttt{a} and \texttt{b} and the number of intevals \texttt{n}
\end{itemize}
\end{itemize}

\begin{verbatim}
#ifndef INTEGRATE_H_
#define INTEGRATE_H_

#include <stddef.h>

typedef float (*integrand_f)(float x, void *ctx);

typedef enum
{
    INTEG_OK = 0,
    INTEG_ERR_BAD_ARGS = -1,
    INTEG_ERR_N_EVEN_REQUIRED = -2
} integ_status_t;

integ_status_t midpoint(integrand_f f, void *ctx, float a, float b, unsigned n,
                        float *out);

integ_status_t trapezoid(integrand_f f, void *ctx, float a, float b, unsigned n,
                         float *out);

integ_status_t simpson(integrand_f f, void *ctx, float a, float b, unsigned n,
                       float *out);

#endif // INTEGRATE_H_
\end{verbatim}
\subsection{\texttt{"integrate.c"}:}
\label{sec:org80dbf09}
Implements the three numerical integration algorithms (midpoint/rectangle, trapezoid, Simpson 1/3) behind the public interface from \texttt{integrate.h}, including argument validation and method-specific constraints.

The file includes \texttt{integrate.h} and provides the concrete implementations of \texttt{midpoint()}, \texttt{trapezoid()}, and \texttt{simpson()}, each computing an approximation of $$I = \int_a^bf(x)dx$$ by sampling the integrand at specific points and summing weighted contributions.

All three functions follow the same reusable calling convention: function pointer \texttt{integrand\_f f}, a generic context pointer \texttt{ctx}, integration bounds \texttt{a}, \texttt{b}, subinterval count \texttt{n}, and output pointer \texttt{out}.

\begin{verbatim}

static inline int bad_args(integrand_f f, float *a, float *b, unsigned *n,
                           float *out)
{
    return (f == NULL || out == NULL || *n == 0u || !(*b > *a));
}

integ_status_t midpoint(integrand_f f, void *ctx, float a, float b, unsigned n,
                        float *out)
{
    /*check if all necessary parameters have been given */
    if (bad_args(f, &a, &b, &n, out))
        return INTEG_ERR_BAD_ARGS;

    float sum = 0.0f;
    float fx = 0.0f;

    /*intervall width h: */
    const float h = (b - a) / (float)n;
    float x = a + 0.5f * h;

    for (unsigned i = 0; i < n; ++i)
    {
        fx = f(x, ctx);
        sum = sum + fx;
        x = x + h;
    }

    *out = sum * h;
    return INTEG_OK;
}

integ_status_t trapezoid(integrand_f f, void *ctx, float a, float b, unsigned n,
                         float *out)
{
    if (bad_args(f, &a, &b, &n, out))
    {
        return INTEG_ERR_BAD_ARGS;
    }

    const float h = (b - a) / (float)n;
    float sum = 0.5f * (f(a, ctx) + f(b, ctx));

    float x = a + h;
    for (unsigned i = 1; i < n; ++i)
    {
        sum = sum + f(x, ctx);
        x = x + h;
    }

    *out = sum * h;
    return INTEG_OK;
}

integ_status_t simpson(integrand_f f, void *ctx, float a, float b, unsigned n,
                       float *out)
{
    if (bad_args(f, &a, &b, &n, out))
    {
        return INTEG_ERR_BAD_ARGS;
    }
    if (n & 1u) /*n must be even*/
    {
        return INTEG_ERR_N_EVEN_REQUIRED;
    }

    float sum_odd = 0.0f;
    float sum_even = 0.0f;
    const float h = (b - a) / (float)n;

    float x = a + h;
    for (unsigned i = 1; i < n; ++i)
    {
        const float fx = f(x, ctx);
        if (i & 1u)
            sum_odd = sum_odd + fx;
        else
            sum_even = sum_even + fx;
        x = x + h;
    }

    *out =
        (h / 3.0f) * (f(a, ctx) + 4.0f * sum_odd + 2.0f * sum_even + f(b, ctx));
    return INTEG_OK;
}
\end{verbatim}
\subsubsection{Common argument checking (\texttt{bad\_args})}
\label{sec:org7e75604}

A shared internal helper \texttt{bad\_args()} is implemented as \texttt{static inline} to reduce call overhead and to allow the compiler to inline it for performance on embedded targets.

It returns an error condition if \texttt{f == NULL, out == NULL, n == 0} or the interval is invalid (the code checks  \texttt{b > a}).
If \texttt{bad\_args()} reports invalid inputs, each public integration function returns \texttt{INTEG\_ERR\_BAD\_ARGS} immediately.
\subsubsection{Midpoint / rectangle method (\texttt{midpoint})}
\label{sec:org9f6d06d}
\begin{enumerate}
\item Mathematical idea
\label{sec:orga069e15}

The interval [a,b] is split into n subintervals of equal width $$h=(b-a)/n$$, and each subinterval [xi,xi+1] is approximated by a rectangle whose height is the function value at the midpoint $$xi+h/2$$.
The Formula is as follows: \cslcitation{1}{[1]}

$$\approx h \sum_{i=1}^n f({x_{i-1}+x_i}/2)$$
\item Implementation details
\label{sec:orga095516}
The code computes \texttt{h}, initializes the first midpoint \texttt{x = a + 0.5fh}, then loops exactly \texttt{n} times, accumulating \texttt{sum = sum + f(x, ctx)} and stepping \texttt{x = x + h}.

Finally, the result is written as \texttt{out = sum * h} and the function returns \texttt{INTEG\_OK}.
\end{enumerate}
\subsubsection{Trapezoid method (\texttt{trapezoid})}
\label{sec:org356a6b8}
\begin{enumerate}
\item Mathematical idea
\label{sec:orgd155bc9}

Each subinterval is approximated by a trapezoid formed by the points $$(xi,f(xi))$$ and $$(xi+1,f(xi+1))$$, giving the composite trapezoid rule.

This corresponds to the standard weighted sum \cslcitation{2}{[2]}
$$ = h/2 (f(x_0)+2f(x_1)+\dots+2f(x_{n-1})+f(x_n))$$
\item Implementation details
\label{sec:org20242c9}

The code computes \texttt{h}, then initializes \texttt{sum = 0.5f*(f(a,ctx)+f(b,ctx))} to apply the half-weight to the endpoints.
It iterates from the first interior node \texttt{x = a + h} for \texttt{i = 1..n-1}, adds each interior sample once (\texttt{sum = sum + f(x,ctx)}), then scales by \texttt{h} via \texttt{*out = sum * h}.
\end{enumerate}
\subsubsection{Simpson 1/3 method (\texttt{simpson})}
\label{sec:orga43d4c9}
\begin{enumerate}
\item Mathematical idea
\label{sec:org4292208}

Simpson's 1/3 rule approximates the function by piecewise quadratic polynomials over pairs of subintervals, which leads to alternating weights 4 and 2 for interior points.

The composite Simpson rule requires an even number of subintervals nn so that the domain can be grouped into $$n/2$$ pairs.
The formula is as such: \cslcitation{3}{[3]}
$$ \approx (h/3) [f(x_0)+4f(x_1)+2f(x_2)+ \dots 2f(x_{n-2})+4f(x_{n-1})+f(x_n)]$$
\item Implementation details and constraint handling
\label{sec:orgb038bbe}

After basic argument validation, the function checks \texttt{if (n \& 1u)} and returns \texttt{INTEG\_ERR\_N\_EVEN\_REQUIRED} if \texttt{n} is odd, enforcing the ``even n'' requirement from the interface contract.

It then loops over the interior nodes \texttt{i=1..n-1} and accumulates two partial sums: \texttt{sum\_odd} for odd indices (weight 4) and \texttt{sum\_even} for even indices (weight 2).
The final formula implemented is \\
\texttt{out = (h/3)(f(a)+4*sum\_odd+2*sum\_even+f(b))}, which matches the documented Simpson weighting scheme.
\end{enumerate}
\subsection{Performance-oriented aspects (embedded focus)}
\label{sec:orgf872e63}

The design avoids dynamic allocation and uses a caller-provided output pointer (\texttt{float *out}), which is predictable and typical for embedded C modules.

The \texttt{ctx} pointer allows passing coefficients/parameters without global variables, enabling reuse for many function types while keeping the integrator code generic.
Using \texttt{static inline} for \texttt{bad\_args} and keeping loop bodies simple (incrementing \texttt{x} by \texttt{h} rather than recomputing from scratch) supports compiler optimization and reduces runtime overhead.

When checking for evenness of \texttt{n} the simpson function uses \texttt{\& u1} instead of \texttt{\% 2}. It is not possible to substitue a \texttt{/2} for a \texttt{>{}>{}1} for the float variable type. Such tricks can not have been used for any values with the float type.
\section{Documentation of the reference examples used for testing}
\label{sec:orgd361433}
\texttt{"main.c"} is a small command-line test application that demonstrates how to use the reusable integration module by defining example integrand functions, calling all three numerical methods, and printing absolute errors against known exact results.

The application includes \texttt{integrate.h} and uses standard library functionality (printing and absolute error via \texttt{fabsf}) to compare the numeric results to a known reference (``exact'') value.
Its purpose is not to be a generic framework, but a compact test harness that exercises the module API and makes method limitations visible at runtime (e.g., Simpson's even-\texttt{n} requirement).
\subsection{Test integrand design}
\label{sec:org7f48d68}
Parameterized quadratic via context pointer

A small struct \texttt{quad\_t} stores coefficients \texttt{a2}, \texttt{a1}, \texttt{a0} for a quadratic polynomial $$f(x)=a_2x^2+a_1x+a_0$$, showing how the integrator's \texttt{void *ctx} can carry user-defined parameters without globals.
The function \texttt{f\_quad(float x, void ctx)} casts \texttt{ctx} to \texttt{const quad\_t} and evaluates the polynomial, matching the generic \texttt{integrand\_f} interface expected by the integration module.
\subsection{Test runner (\texttt{run\_one})}
\label{sec:org700fda6}

The helper \texttt{run\_one(...)} calls \texttt{midpoint}, \texttt{trapezoid}, and \texttt{simpson} with the same function, bounds, and number of subintervals, storing results into three local floats (\texttt{r}, \texttt{t}, \texttt{s}).
It prints the integration problem setup (function name, bounds, \texttt{n}), prints the exact reference value, and prints each method's absolute error using \texttt{fabsf(result - exact)} for a direct precision comparison.
Simpson's status return is checked: if \texttt{simpson} returns \texttt{INTEG\_OK}, the Simpson result/error is printed, otherwise a message is printed indicating it was not computed because \texttt{n} must be even.
\subsection{Reference examples in \texttt{main()}}
\label{sec:org8334b01}

Four concrete test cases are instantiated using \texttt{quad\_t} coefficients and passed to \texttt{run\_one}.
They have been chosen in such a way that many edge cases are accounted for.



Example 1: \texttt{q} $$f(x)=x^2$$ on [0,1] with exact integral 1/3 and \texttt{n=10} 
\begin{center}
\includegraphics[width=.9\linewidth]{./q.png}
\end{center}

Example 2: \texttt{q2} $$f(x)=-x2+3x+50$$ on [-3,15] with exact integral 90 and \texttt{n=22} 
\begin{center}
\includegraphics[width=.9\linewidth]{./q2.png}
\end{center}

Example 3: \texttt{q3} $$f(x)=-9x^2+3x-100$$ on [12,15] with exact integral -5119.5 and \texttt{n=2}
\begin{center}
\includegraphics[width=.9\linewidth]{./q3.png}
\end{center}

Example 4: \texttt{q4} $$f(x)=6x^2-10x$$ on [-50,-5] with exact integral 262125 and \texttt{n=6u}
\begin{center}
\includegraphics[width=.9\linewidth]{./q4.png}
\end{center}
\begin{verbatim}
#ifndef INTEGRATE_H_
#define INTEGRATE_H_

#include <stddef.h>

typedef float (*integrand_f)(float x, void *ctx);

typedef enum
{
    INTEG_OK = 0,
    INTEG_ERR_BAD_ARGS = -1,
    INTEG_ERR_N_EVEN_REQUIRED = -2
} integ_status_t;

integ_status_t midpoint(integrand_f f, void *ctx, float a, float b, unsigned n,
                        float *out);

integ_status_t trapezoid(integrand_f f, void *ctx, float a, float b, unsigned n,
                         float *out);

integ_status_t simpson(integrand_f f, void *ctx, float a, float b, unsigned n,
                       float *out);

#endif // INTEGRATE_H_

static inline int bad_args(integrand_f f, float *a, float *b, unsigned *n,
                           float *out)
{
    return (f == NULL || out == NULL || *n == 0u || !(*b > *a));
}

integ_status_t midpoint(integrand_f f, void *ctx, float a, float b, unsigned n,
                        float *out)
{
    /*check if all necessary parameters have been given */
    if (bad_args(f, &a, &b, &n, out))
        return INTEG_ERR_BAD_ARGS;

    float sum = 0.0f;
    float fx = 0.0f;

    /*intervall width h: */
    const float h = (b - a) / (float)n;
    float x = a + 0.5f * h;

    for (unsigned i = 0; i < n; ++i)
    {
        fx = f(x, ctx);
        sum = sum + fx;
        x = x + h;
    }

    *out = sum * h;
    return INTEG_OK;
}

integ_status_t trapezoid(integrand_f f, void *ctx, float a, float b, unsigned n,
                         float *out)
{
    if (bad_args(f, &a, &b, &n, out))
    {
        return INTEG_ERR_BAD_ARGS;
    }

    const float h = (b - a) / (float)n;
    float sum = 0.5f * (f(a, ctx) + f(b, ctx));

    float x = a + h;
    for (unsigned i = 1; i < n; ++i)
    {
        sum = sum + f(x, ctx);
        x = x + h;
    }

    *out = sum * h;
    return INTEG_OK;
}

integ_status_t simpson(integrand_f f, void *ctx, float a, float b, unsigned n,
                       float *out)
{
    if (bad_args(f, &a, &b, &n, out))
    {
        return INTEG_ERR_BAD_ARGS;
    }
    if (n & 1u) /*n must be even*/
    {
        return INTEG_ERR_N_EVEN_REQUIRED;
    }

    float sum_odd = 0.0f;
    float sum_even = 0.0f;
    const float h = (b - a) / (float)n;

    float x = a + h;
    for (unsigned i = 1; i < n; ++i)
    {
        const float fx = f(x, ctx);
        if (i & 1u)
            sum_odd = sum_odd + fx;
        else
            sum_even = sum_even + fx;
        x = x + h;
    }

    *out =
        (h / 3.0f) * (f(a, ctx) + 4.0f * sum_odd + 2.0f * sum_even + f(b, ctx));
    return INTEG_OK;
}

#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;
}
\end{verbatim}
\subsubsection{Results}
\label{sec:orga992d73}
\section{Bibliography}
\label{sec:orgab8c92c}
\begin{cslbibliography}{0}{0}
\cslbibitem{1}{\cslleftmargin{[1]}\cslrightinline{“Engineering at Alberta Courses Rectangle Method,” Jan. 2026. Available: \url{https://engcourses-uofa.ca/books/numericalanalysis/numerical-integration/rectangle-method}}}

\cslbibitem{2}{\cslleftmargin{[2]}\cslrightinline{“Engineering at Alberta Courses Trapezoidal Rule,” Jan. 2026. Available: \url{https://engcourses-uofa.ca/books/numericalanalysis/numerical-integration/trapezoidal-rule}}}

\cslbibitem{3}{\cslleftmargin{[3]}\cslrightinline{“Simpson’s Rule (Simpson’s 1/3 Rule) - Formula, Derivation, Examples,” Jan. 2026. Available: \url{https://www.cuemath.com/simpsons-rule-formula}}}

\end{cslbibliography}
\end{document}
