commit 0a9c6df07087dc30545a88a6fd1d78a85d41ea7d Author: rh17s15 Date: Tue Jan 27 15:19:22 2026 +0100 2026-01-27T15:19:25 diff --git a/.auctex-auto/bib.el b/.auctex-auto/bib.el new file mode 100644 index 0000000..d8a7b51 --- /dev/null +++ b/.auctex-auto/bib.el @@ -0,0 +1,11 @@ +;; -*- lexical-binding: t; -*- + +(TeX-add-style-hook + "bib" + (lambda () + (LaTeX-add-bibitems + "Midpoint" + "Trapez" + "Simpson")) + '(or :bibtex :latex)) + diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..d5663a2 --- /dev/null +++ b/.clang-format @@ -0,0 +1,8 @@ +--- +Language: Cpp +BasedOnStyle: LLVM +IndentWidth: 4 +UseTab: Never +BreakBeforeBraces: Allman +ColumnLimit: 80 +... diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..936fa4c --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +.DS_Store +.idea +*.log +tmp/ +.gdb_history diff --git a/AutoSW_Kronner_Topic-5.zip b/AutoSW_Kronner_Topic-5.zip new file mode 100644 index 0000000..f8d0663 Binary files /dev/null and b/AutoSW_Kronner_Topic-5.zip differ diff --git a/README.md b/README.md new file mode 100644 index 0000000..fd6e4fc --- /dev/null +++ b/README.md @@ -0,0 +1,11 @@ + Topic 5: Numerical integration methods + +compile with: +```bash +make clean +``` + +run with: +```bash +./main +``` diff --git a/bib.bib b/bib.bib new file mode 100644 index 0000000..3e94b1b --- /dev/null +++ b/bib.bib @@ -0,0 +1,24 @@ +@misc{Midpoint, + title = {{Engineering at Alberta Courses {\ifmmode\mbox{\guillemotright}\else\guillemotright\fi} Rectangle Method}}, + year = {2026}, + month = jan, + note = {[Online; accessed 15. Jan. 2026]}, + url = {https://engcourses-uofa.ca/books/numericalanalysis/numerical-integration/rectangle-method} +} + +@misc{Trapez, + title = {{Engineering at Alberta Courses {\ifmmode\mbox{\guillemotright}\else\guillemotright\fi} Trapezoidal Rule}}, + year = {2026}, + month = jan, + note = {[Online; accessed 15. Jan. 2026]}, + url = {https://engcourses-uofa.ca/books/numericalanalysis/numerical-integration/trapezoidal-rule} +} + +@misc{Simpson, + title = {{Simpson's Rule (Simpson's 1/3 Rule) - Formula, Derivation, Examples}}, + journal = {Cuemath}, + year = {2026}, + month = jan, + note = {[Online; accessed 15. Jan. 2026]}, + url = {https://www.cuemath.com/simpsons-rule-formula} +} diff --git a/documentation.bbl b/documentation.bbl new file mode 100644 index 0000000..005f385 --- /dev/null +++ b/documentation.bbl @@ -0,0 +1,20 @@ +% $ biblatex auxiliary file $ +% $ biblatex bbl format version 3.2 $ +% Do not modify the above lines! +% +% This is an auxiliary file used by the 'biblatex' package. +% This file may safely be deleted. It will be recreated by +% biber as required. +% +\begingroup +\makeatletter +\@ifundefined{ver@biblatex.sty} + {\@latex@error + {Missing 'biblatex' package} + {The bibliography requires the 'biblatex' package.} + \aftergroup\endinput} + {} +\endgroup + +\endinput + diff --git a/documentation.org b/documentation.org new file mode 100644 index 0000000..dd4238c --- /dev/null +++ b/documentation.org @@ -0,0 +1,345 @@ +#+title: Documentation for AutoSW +#+title: Topic 5: Numerical integration methods +#+author: Mia Kronner +#+author: Matr. 22201686 +#+options: email:nil + +#+bibliography: ./bib.bib + +#+LATEX_HEADER: \let\oldsection\section +#+LATEX_HEADER: \renewcommand{\section}{\clearpage\oldsection} +#+LATEX_HEADER: \let\oldsubsection\subsection +#+LATEX_HEADER: \renewcommand{\subsection}{\clearpage\oldsubsection} + +* Declaration of self reliance +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. + +* Graphical representation of the software design + + +#+BIND: org-latex-images-centered nil +#+ATTR_LATEX: \textwidth :float nil +[[./graphical-representation-white.drawio.png]] + +* Theoretical explanation of the relationships +** ~"integrate.h"~: +Interface for ~integrate.c~ Module. +Here is declared: +- a void float function pointer for the mathematical function which is to be integrated ~integrand_f~. +- a typedef which contains the possible return values for the three integration functions ~integ_status_t~ +- the three integration functions ~midpoint~ (rectangle midpoint method), ~trapezoid~ (trapezoid method), and ~simpson~ (simpson 1/3 method) + + they each take a integrand function ~integrand_f f~, its context as a void pointer ~void *ctx~, the limits ~a~ and ~b~ and the number of intevals ~n~ + +#+name: integrate.h +#+begin_src C :noweb-ref integrate.h +#ifndef INTEGRATE_H_ +#define INTEGRATE_H_ + +#include + +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_src + +** ~"integrate.c"~: +Implements the three numerical integration algorithms (midpoint/rectangle, trapezoid, Simpson 1/3) behind the public interface from ~integrate.h~, including argument validation and method-specific constraints. + +The file includes ~integrate.h~ and provides the concrete implementations of ~midpoint()~, ~trapezoid()~, and ~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 ~integrand_f f~, a generic context pointer ~ctx~, integration bounds ~a~, ~b~, subinterval count ~n~, and output pointer ~out~. + +#+name: integrate.c +#+begin_src C :noweb-ref integrate.c + +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_src + +*** Common argument checking (~bad_args~) + +A shared internal helper ~bad_args()~ is implemented as ~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 ~f == NULL, out == NULL, n == 0~ or the interval is invalid (the code checks ~b > a~). +If ~bad_args()~ reports invalid inputs, each public integration function returns ~INTEG_ERR_BAD_ARGS~ immediately. + +*** Midpoint / rectangle method (~midpoint~) +**** Mathematical idea + +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: [cite:@Midpoint] + +$$\approx h \sum_{i=1}^n f({x_{i-1}+x_i}/2)$$ + +**** Implementation details +The code computes ~h~, initializes the first midpoint ~x = a + 0.5fh~, then loops exactly ~n~ times, accumulating ~sum = sum + f(x, ctx)~ and stepping ~x = x + h~. + +Finally, the result is written as ~out = sum * h~ and the function returns ~INTEG_OK~. + +*** Trapezoid method (~trapezoid~) +**** Mathematical idea + +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 [cite:@Trapez] +$$ = h/2 (f(x_0)+2f(x_1)+\dots+2f(x_{n-1})+f(x_n))$$ +**** Implementation details + +The code computes ~h~, then initializes ~sum = 0.5f*(f(a,ctx)+f(b,ctx))~ to apply the half-weight to the endpoints. +It iterates from the first interior node ~x = a + h~ for ~i = 1..n-1~, adds each interior sample once (~sum = sum + f(x,ctx)~), then scales by ~h~ via ~*out = sum * h~. +*** Simpson 1/3 method (~simpson~) +**** Mathematical idea + +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: [cite:@Simpson] +$$ \approx (h/3) [f(x_0)+4f(x_1)+2f(x_2)+ \dots 2f(x_{n-2})+4f(x_{n-1})+f(x_n)]$$ + +**** Implementation details and constraint handling + +After basic argument validation, the function checks ~if (n & 1u)~ and returns ~INTEG_ERR_N_EVEN_REQUIRED~ if ~n~ is odd, enforcing the "even n" requirement from the interface contract. + +It then loops over the interior nodes ~i=1..n-1~ and accumulates two partial sums: ~sum_odd~ for odd indices (weight 4) and ~sum_even~ for even indices (weight 2). +The final formula implemented is \\ +~out = (h/3)(f(a)+4*sum_odd+2*sum_even+f(b))~, which matches the documented Simpson weighting scheme. + +** Performance-oriented aspects (embedded focus) + +The design avoids dynamic allocation and uses a caller-provided output pointer (~float *out~), which is predictable and typical for embedded C modules. + +The ~ctx~ pointer allows passing coefficients/parameters without global variables, enabling reuse for many function types while keeping the integrator code generic. +Using ~static inline~ for ~bad_args~ and keeping loop bodies simple (incrementing ~x~ by ~h~ rather than recomputing from scratch) supports compiler optimization and reduces runtime overhead. + +When checking for evenness of ~n~ the simpson function uses ~& u1~ instead of ~% 2~. It is not possible to substitue a ~/2~ for a ~>>1~ for the float variable type. Such tricks can not have been used for any values with the float type. + +* Documentation of the reference examples used for testing +~"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 ~integrate.h~ and uses standard library functionality (printing and absolute error via ~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-~n~ requirement). + +** Test integrand design +Parameterized quadratic via context pointer + +A small struct ~quad_t~ stores coefficients ~a2~, ~a1~, ~a0~ for a quadratic polynomial $$f(x)=a_2x^2+a_1x+a_0$$, showing how the integrator's ~void *ctx~ can carry user-defined parameters without globals. +The function ~f_quad(float x, void ctx)~ casts ~ctx~ to ~const quad_t~ and evaluates the polynomial, matching the generic ~integrand_f~ interface expected by the integration module. + +** Test runner (~run_one~) + +The helper ~run_one(...)~ calls ~midpoint~, ~trapezoid~, and ~simpson~ with the same function, bounds, and number of subintervals, storing results into three local floats (~r~, ~t~, ~s~). +It prints the integration problem setup (function name, bounds, ~n~), prints the exact reference value, and prints each method's absolute error using ~fabsf(result - exact)~ for a direct precision comparison. +Simpson's status return is checked: if ~simpson~ returns ~INTEG_OK~, the Simpson result/error is printed, otherwise a message is printed indicating it was not computed because ~n~ must be even. + +** Reference examples in ~main()~ + +Four concrete test cases are instantiated using ~quad_t~ coefficients and passed to ~run_one~. +They have been chosen in such a way that many edge cases are accounted for. + + + +Example 1: ~q~ $$f(x)=x^2$$ on [0,1] with exact integral 1/3 and ~n=10~ +[[./q.png]] + +Example 2: ~q2~ $$f(x)=-x2+3x+50$$ on [-3,15] with exact integral 90 and ~n=22~ +[[./q2.png]] + +Example 3: ~q3~ $$f(x)=-9x^2+3x-100$$ on [12,15] with exact integral -5119.5 and ~n=2~ +[[./q3.png]] + +Example 4: ~q4~ $$f(x)=6x^2-10x$$ on [-50,-5] with exact integral 262125 and ~n=6u~ +[[./q4.png]] +#+name: main.c +#+begin_src C :noweb yes :results output :flags -g -fanalyzer +<> +<> + +#include +#include + +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_src + +*** Results +#+RESULTS: main.c +#+begin_results +x^2 on [0.000000, 1.000000], n=10 +Exact: 0.333333343 +Midpoint: 0.332500070 err=0.000833273 +Trapezoid: 0.335000038 err=0.001666695 +Simpson: 0.333333373 err=0.000000030 + +x^2+3x+50 on [-3.000000, 15.000000], n=22 +Exact: 90.000000000 +Midpoint: 91.004028320 err=1.004028320 +Trapezoid: 87.991584778 err=2.008415222 +Simpson: 89.999839783 err=0.000160217 + +-9x^2+3x-100 on [12.000000, 15.000000], n=2 +Exact: -5119.500000000 +Midpoint: -5114.437500000 err=5.062500000 +Trapezoid: -5129.625000000 err=10.125000000 +Simpson: -5119.500000000 err=0.000000000 + +6x^2-10x on [-50.000000, -5.000000], n=6 +Exact: 262125.000000000 +Midpoint: 260859.375000000 err=1265.625000000 +Trapezoid: 264656.250000000 err=2531.250000000 +Simpson: 262125.000000000 err=0.000000000 +#+end_results + + + + +* Bibliography +#+CITE_EXPORT: csl ./ieee.csl +#+print_bibliography: diff --git a/documentation.pdf b/documentation.pdf new file mode 100644 index 0000000..71c0ac3 Binary files /dev/null and b/documentation.pdf differ diff --git a/documentation.tex b/documentation.tex new file mode 100644 index 0000000..32f8c73 --- /dev/null +++ b/documentation.tex @@ -0,0 +1,501 @@ +% Created 2026-01-27 Di 15:08 +% 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:orgf1c5ba4} +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{Graphical representation of the software design} +\label{sec:orgf50f0e3} + + +\begin{center} +\includegraphics[width=.9\linewidth]{./graphical-representation-white.drawio.png} +\end{center} +\section{Theoretical explanation of the relationships} +\label{sec:org15650c5} +\subsection{\texttt{"integrate.h"}:} +\label{sec:orgc09841a} +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 + +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:orgbe94578} +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:org5576bb4} + +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:orgb278e27} +\begin{enumerate} +\item Mathematical idea +\label{sec:orgd41c3d4} + +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:orgebae471} +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:orga8108f1} +\begin{enumerate} +\item Mathematical idea +\label{sec:org31aecc1} + +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:org36dc554} + +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:org6457a29} +\begin{enumerate} +\item Mathematical idea +\label{sec:orgd9bfe20} + +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:org4ce84b4} + +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:org5f114cd} + +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:org2d1f7ee} +\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:org3cbabb2} +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:org010d856} + +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:orgd2d9b7a} + +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 + +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 +#include + +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:org8a0d097} +\section{Bibliography} +\label{sec:org8cd8f85} +\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} diff --git a/graphical-representation-black.drawio.png b/graphical-representation-black.drawio.png new file mode 100644 index 0000000..f14dbb1 Binary files /dev/null and b/graphical-representation-black.drawio.png differ diff --git a/graphical-representation-white.drawio.png b/graphical-representation-white.drawio.png new file mode 100644 index 0000000..af6cffb Binary files /dev/null and b/graphical-representation-white.drawio.png differ diff --git a/graphical-representation.drawio b/graphical-representation.drawio new file mode 100644 index 0000000..1200ab4 --- /dev/null +++ b/graphical-representation.drawio @@ -0,0 +1,202 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ieee.csl b/ieee.csl new file mode 100644 index 0000000..7612c15 --- /dev/null +++ b/ieee.csl @@ -0,0 +1,519 @@ + + diff --git a/integrate.c b/integrate.c new file mode 100644 index 0000000..9c2461f --- /dev/null +++ b/integrate.c @@ -0,0 +1,90 @@ +#include "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) +{ + /*check if all necessary parameters have been given */ + if (bad_args(f, &a, &b, &n, out)) + { + return INTEG_ERR_BAD_ARGS; + } + + /*intervall width h: */ + 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) +{ + /*check if all necessary parameters have been given */ + 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; + /*intervall width h: */ + 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; +} diff --git a/integrate.h b/integrate.h new file mode 100644 index 0000000..15ab1ea --- /dev/null +++ b/integrate.h @@ -0,0 +1,24 @@ +#ifndef INTEGRATE_H_ +#define INTEGRATE_H_ + +#include + +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_ diff --git a/integrate.o b/integrate.o new file mode 100644 index 0000000..5062f65 Binary files /dev/null and b/integrate.o differ diff --git a/main b/main new file mode 100755 index 0000000..61720b6 Binary files /dev/null and b/main differ diff --git a/main.c b/main.c new file mode 100644 index 0000000..641d4e1 --- /dev/null +++ b/main.c @@ -0,0 +1,56 @@ +#include "integrate.h" +#include +#include + +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; +} diff --git a/main.o b/main.o new file mode 100644 index 0000000..188d309 Binary files /dev/null and b/main.o differ diff --git a/makefile b/makefile new file mode 100644 index 0000000..ebf9144 --- /dev/null +++ b/makefile @@ -0,0 +1,22 @@ +#Makefile + +CC=gcc +CFLAGS=-g -fanalyzer +# CFLAGS= -fanalyzer +# LIBS=-lsodium -larchive + +SRC_FILES=main.c integrate.c +OBJ_FILES=$(SRC_FILES:.c=.o) + +TARGET=main + +$(TARGET): $(OBJ_FILES) + $(CC) $(CFLAGS) $(OBJ_FILES) $(LIBS) -o $(TARGET) + +%.o: %.c + $(CC) $(CFLAGS) -c $< -o $@ + +.PHONY: clean +clean: + rm -f $(OBJ_FILES) +# rm -f $(OBJ_FILES) $(TARGET) diff --git a/notes.org b/notes.org new file mode 100644 index 0000000..9704c16 --- /dev/null +++ b/notes.org @@ -0,0 +1,407 @@ +* PoP +| 1 | M | Fixed Point Arithmetic | Single Person | max 5x | +| 2 | | General fast exponentation according to Legendre / square root with Newton iteration | Single Person | max 3x | +| 3 | M | NVM Manager | 2 | max 3x | +| 4 | M | Multiport RAM Interface MPRAM-Interface | Single Person | max 3x | +| 5 | | Numerical integration methods | Single Person | max 3x | +with callback function, uses function pointer +was mit power of two is sufficient +| 6 | M | Djikstra algorithm | Single Person | max 5x | +5-7 nodes +| 8 | M | Online methods - Variance according to Welford and arithmetic mean | Single person | max 5x | +| 9 | | Message-based intertask communication | 2 | max 2x | + + +Numerical integration methods + +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 +- Graphical representation of the software design and compact description of the key relationships (1 page) +- Theoretical explanation of the relationships (mathematical, algorithmic, etc.) that need to be taken into account here (2 pages) +- Documentation of the reference examples used for testing, with graphical representation and explanation of method limitations (2 pages) + + +** Notizen zu Folien + +*** keine Unions +*** enum + +Implizite Deklaration: +#+begin_src c +enum t_AlgoEnumVals{ +INIT = 0u, +RUNNING = 1u, +WAITING = 2u, +INVALID = 3u +}; +#+end_src +-> definiert nur den Typnamen enum t_AlgoEnumVals, reserviert aber keinen Speicher, solange keine Variable dieses Typs definiert wird. + +Explizite Deklaration: +#+begin_src c +typedef enum{ +INIT = 0u, +RUNNING = 1u, +WAITING = 2u, +INVALID = 3u +} t_AlgoEnumVals; +#+end_src + +-> macht das Gleiche, nur dass der Typ danach über den Alias t_AlgoEnumVals ohne enum verwendet werden kann; auch hier entsteht Speicher erst bei Variablen/Objekten dieses Typs. + +*** kombination union und struct + +#+begin_src c +typedef unsigned char t_BYTE; +typedef unsigned short t_WORD; +typedef unsigned long t_DWORD; + +#pragma pack(1) + +typedef struct{ +t_BYTE Wert0; +t_BYTE Wert1; +t_BYTE Wert2; +t_WORD Wert3; +t_DWORD Wert4; +t_DWORD Wert5; +t_DWORD Wert6; +t_WORD Wert7; +t_BYTE Wert8; +}t_Struct; + +typedef union{ +t_BYTE vbyArray[20]; +t_Struct stStruct; +}t_unStructUnion; + +#pragma pack() +#+end_src + +-> see 05 P9 + +*** Funktionsaufrufe + + Call by Value: + #+begin_src c +int func1(int par1, int par2){ + return(par1*par2); +} + +void main(void){ + int a = 0; + + // function call by value: + a = func1(5,3); + + printf("Result %d\n",a); +} + #+end_src + -> Werte werden über Stack direkt übergeben. + +Call by Reference: + #+begin_src c +int func1(int par1, int par2){ + *par1 = 5; + *par2 = 2; +} + +void main(void){ + int a, b = 0; + + // function call by reference: + func1(&a, &b); + + printf("Result %d, %d\n", a, b); +} + #+end_src +-> Referenzen auf Variablen werden übergeben. + Variablen sind im Hauptprogramm deklariert und definiert. + + +Es ist möglich für sehr schnelle Operation Register für Übergabe von Parametern benutzen. +Schlüsselwort Speicherklassenangabe /register/ + +Übergabe eines Arrays: +#+begin_src c +int func3(unsigned char * DataArray, unsigned short *DataLength){ + int iRet = 0; + if (DataArray[0] == 0x55 && DataArray[1] == 0x33){ + /* Do someting*/ + } + else { + iRet = -1; /* Wrong Header in array */ + } + return(iRet); +} +#+end_src + + +Aufruf im Hauptprogramm (bitte die Dereferenzierung beachten) +#+begin_src c +//… +iRet = func3(&vbyData[0], &usDataLength); +//… +#+end_src + +*** Rückgabewerte +nur für Fehler +Erfolg ist 0 +#+begin_src c +int iRet = 0; +iRet = func1(&DataArray[0], &DataLength); +if(iRet <0){ + /* … Fehlerbehandlung … */ +} +#+end_src + +*** Pointer +#+begin_src c +return_type function (xx_type const * pParam) +#+end_src +Beispiel: +(1) pParam ist ein +(2) Zeiger auf eine +(3) Konstante vom Typ +(4) xx_type + +Zeiger auf Konstante: Eine Wertzuweisung ist nicht erlaubt/möglich (z.B. +~*pParam = 1.1f;~). + +#+begin_src c +t_BYTE Data[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 }; +t_BYTE *pData = &Data[0]; /* Data anstelle von &Data[0] moeglich */ +/* pData = (t_BYTE *) &Data[0]; */ +/* Adresszuweisung, der cast ist nicht zwingend notwendig */ +printf("Der Pointer zeigt auf 0x%X mit dem Inhalt %d\n", pData, *pData); +pData++; +printf("Der Pointer zeigt auf 0x%X mit dem Inhalt %d\n", pData, *pData); +printf("Array Adresse: 0x%X 0x%x\n", &pData[0], &pData[1]); +#+end_src + +*** Pointer Arithmetic +#+begin_src c +t_BYTE vbyData[20] = { 0x00 }; +t_BYTE *pvbyData=NULL; +for (int i = 0; i < sizeof(vbyData); i++){ /* Init Array */ + vbyData[i] = i+1; +} +pvbyData = (t_BYTE *) &vbyData[0]; +/* Adresszuweisung, der cast ist nicht notwendig */ + +for (int i = 0; i < 10; i++){ + printf("0x%X ", *pvbyData); + pvbyData++; +} +printf("\n"); +for (int i = 10; i > 5; i--){ + printf("0x%X ", *pvbyData); + pvbyData--; +} +printf("\n"); +#+end_src + +*** Pointer to struct +#+begin_src c +typedef struct strData{ + t_WORD w1; + t_WORD w2; +}; + +strData strDataValue; +strData * pstrDataValue = NULL; + +pstrDataValue = &strDataValue; + +strDataValue.w1 = 0xAAEE; +strDataValue.w2 = 0xDDFF; + +printf("Struct Adresse: 0x%X\n", &strDataValue); +printf("Struct Adresse Pointer 0x%X\n", pstrDataValue); +printf("Struct Inhalt, via Pointer 0x%X 0x%X\n", pstrDataValue->w1,pstrDataValue->w2); +printf("Wertausgabe ueber Pointer 0x%X\n", (*pstrDataValue).w1); +#+end_src + +für verschachtelten struct siehe 06 P9 + +Zeiger auf Array, Interpretation als struct siehe 06 P10 + +*** function pointer + +brauche ich für callback funktion + +#+begin_src c +typedef void(*func)(int *par1, int *par2); + +void func1(int *par1, int *par2){ + *par1 = 5; + *par2 = 3; +} +void main(void){ + func pFunc = NULL; + pFunc = func1; + pFunc(&a, &b); + printf("Werte %d, %d\n", a, b); +} +#+end_src + +Funktionszeiger werden eingesetzt bei der Registrierung von Callback Funktion einer übergeordneten Softwareschicht als Meldemedium für die unterlagerte Softwareschicht. + +Funktionszeiger werden eingesetzt bei der Realisierung generischer Interfaces. + +#+begin_src c +typedef int (*operation_ptr)(int,int); +int add(int a, int b) {return a + b;} +int mult(int a, int b) {return a * b;} + +// or +//int do_operation(operation_ptr op, int x, int x){ +int do_operation(int (*op)(int,int),int x, int y){ + return op(x,y); +} + +int main(int argc, char **argv){ + int results = do_operation(add, 5, 34); + int results2 = do_operation(mult, 2,3); +} +#+end_src + +*** UML +Mindestens jede Komponente, die aus mehreren Modulen bestehen kann, bekommt ein +Design, z.B. in UML (Enterprise Architekt). +*** Design for Testability: +Software soll bereits im Design die Testbarkeit berücksichtigen (STUB- +Barkeit, Datenaustausch per definiertem Interface, einfache Instrumentalisierung ohne die +Laufzeit zu beeinflussen, …) +*** Strukturierung eines Moduls +**** Sourcefile +- Headerkommentar: + Was für ein Modul, Copyright Notice, Versionierung des Moduls, …) +- Includes: + Es werden nur unterlagerte includes eingebunden mit Ausnahme weniger globaler Header +- Macros: + modullokal +- Typedefs: + modullokal +- Constants: + modullokal +- Global variables: + modullokal +- Prototypes: + modullokal +- Functions: + Der Kommentarblock enthält: + - Funktionsname, + - Beschreibung inkl. Bereichsgrenzen der Eingangs und Ausgangsvariablen, + - Beschreibung des Rückgabewertes, + - Beschreibung ggf. globaler verwendeter Variablen, + - Angabe des Erstellers, der Funktion und Datum der Erstellung. + - Jede Änderung der Funktion wird mit Datum und Name kommentiert +- EOF: + Modulfooter +- Jede Sektion wird durch einen Kommentar eingeleitet +- Eine Funktion GetVersion() zur Rückgabe der Modulversion ist verpflichtend. + ~#define MAJOR_VERSION 01~ + ~#define MINOR_VERSION 00~ + ~#define PATCH_VERSION 00~ +- Es ist wichtig ein eindeutiges Versionierungsschema möglichst früh zu vereinbaren. +- Die Anzahl der Codezeilen pro C-Datei soll 1000 NCLOC (Non Comment Lines Of Code) nicht überschreiten. +- Die Anzahl der NCLOC (Non Comment Lines Of Code) pro Funktion soll 100 nicht überschreiten. +- Globale Variablen sind grundsätzlich zu vermeiden, so wenig wie möglich. +- Globale oder modulglobale Variablen und Strukturen sollten grundsätzlich in einer MSN_Init() Funktion zur Laufzeit initialisiert werden. Dies ermöglicht es die Komponente mehrmals im Programmablauf wieder auf den Ausgangszustand zurückzusetzen, was v.a. bei Modultests sehr hilfreich ist. +**** Gruppierung modulglobaler Statusvariablen mittels struct +Guter Designstil ist es den internen Status eines Moduls in einer Struktur zu kapseln. +#+begin_src c +unsigned char ucStateCounter1; +unsigned long ulWorkingClock; +unsigned long ulMsSinceStartup; +unsigned char ucStage; +int iGlobalError; +unsigned char ucStatus; +#+end_src +-> +#+begin_src c +typedef struct { + unsigned char ucStateCounter1; + unsigned long ulWorkingClock; + unsigned long ulMsSinceStartup; + unsigned char ucStage; + int iGlobalError; + unsigned char ucStatus; +}t_GlobalState; + +t_GlobalState GlbState; +#+end_src + +- Lesbarkeit: + Ein gut dokumentierter struct erleichtert an zentraler Stelle den Einstieg in die internen Abläufe des Moduls + Die relevanten modulglobalen Variablen sind an zentraler Stelle zusammengefasst. +- Debugability: + Das Debuggen wird erleichtert, es muss nur eine Struktur in das WatchWindow gezogen werden. +- Testability: + Der interne Status des Moduls lässt sich einfach serialisieren und über eine Kommunikationsschnittstelle übertragen für zum Beispiel eine messtechnische Verwendung. +**** Headerfiles +- Das zu einem Modul gehörende Headerfile bildet das Interface nach außen. Hier wird nur das abgebildet, was zur Verwendung des Moduls von außen benötigt wird. +- Das Headerfile beginnt mit einem Include Guard, um Mehrfachinkludierung zu vermeiden. + ~#ifndef GRANDFATHER_H~ + ~#define GRANDFATHER_H~ +- Globale Variablen dürfen im Headerfile nur deklariert werden aber nicht definiert werden. + Beispiel: ~extern int iTest;~ +- Externe Funktionen dürfen in einem Headerfile nur deklariert aber nicht definiert werden + Beispiel: ~extern void func (void);~ + Anmerkung: + Eine Ausnahme gilt für inline Funktionen. +- Ein Modul bekommt zwei Headerfiles: +➔ Modulename.h +Interface (Deklaration) für das überlagerte Modul +➔ Modulename_cfg.h +Konfigurationsinterface für das Modul (#define) +- Ein Modul wird so aufgebaut, dass ein Dritter der das Modul verwendet, nur die Headerfiles als Interface benötigt, um mit dem Modul arbeiten zu können. +- Im Headerfile deklarierte globale Variablen und Funktionen wird eine Modulkurzkennung bestehend aus drei Buchstaben gefolgt von „_“ vorangestellt. + Beispiel: + ~MSN_TestFunc(…)~ + MSN steht für „Module Short Name“ +− Tailoring: + Im Konfigurationsheader ist ein Tailoring (Anpassung) einer SW-Komponenten auf den aktuellen Verwendungskontext vorzunehmen. +− Tailoring optional: + Ausprogrammierung plattform-spezifischer Funktionsinhalte mittels gesondertem _cfg.c file, das über den cfg.h eingebunden wird. + +*** Kommentare +- Es gibt zwei Arten um einen Kommentar zu markieren: + den mit ~// eingeleiteten C++ Kommentar~ + den in ~/* geklammerten C Kommentar */~ +- Für automotive embedded Templates wird nur der C Kommentarstil vereinbart. + +** Rectangle Method +$$I_2=\int_b^af(x)fx$$ + +$$\approx h \sum_{i=1}^n f({x_{i-1}+x_i}/2)$$ + +** Trapezoid Method +$$I_T = \int_a^b f(x)dx$$ + +$$ \approx h/2 \sum_{i=1}^{n}f(x_{i-1})+f(x_i))$$ + +$$ = h/2 (f(x_0)+2f(x_1)+\dots+2f(x_{n-1})+f(x_n))$$ + +** Simpson Method + +$$I = \int_a^bf(x)dx$$ +$$ \approx (h/3) [f(x_0)+4f(x_1)+2f(x_2)+ \dots 2f(x_{n-2})+4f(x_{n-1})+f(x_n)]$$ + diff --git a/q.png b/q.png new file mode 100644 index 0000000..494e206 Binary files /dev/null and b/q.png differ diff --git a/q2.png b/q2.png new file mode 100644 index 0000000..17aa495 Binary files /dev/null and b/q2.png differ diff --git a/q3.png b/q3.png new file mode 100644 index 0000000..cd3199e Binary files /dev/null and b/q3.png differ diff --git a/q4.png b/q4.png new file mode 100644 index 0000000..ddc418d Binary files /dev/null and b/q4.png differ diff --git a/test.drawio.svg b/test.drawio.svg new file mode 100644 index 0000000..81697cc --- /dev/null +++ b/test.drawio.svg @@ -0,0 +1,4 @@ + + + +
"integrate.h"
"integrate.h"
declaration of integrant function pointer
declaration of integrant funct...
enum for function return values
enum for function return values
deklaration function midpoint
deklaration function midpoint
deklaration function trapezoid
deklaration function trapezoid
deklaration function simpson
deklaration function simpson
"integrate.c"
"integrate.c"
function to check for missing arguments in function
function to check for missing arguments in fun...
midpoint rectangle integration method
midpoint rectangle integration meth...
trapez integration method
trapez integration method
simpson 1/3 integration method
simpson 1/3 integration method
"main.c"
"main.c"
quad_t: typedef struct für berechnungs funktion (austauschbar)
quad_t: typedef struct für berechnungs funktion (austauschbar)
f_quad: berechnungsfunktion für quadratische funktionen (ax^2+a1x+a0) (austauschbar)
f_quad: berechnungsfunktion für quadratische funktionen (ax^2+a1x+a0) (austauschbar)
run_one: funktion die testweise eine funktion in allen methoden integriert und ergebnisse ausgibt
run_one: funktion die testweise eine funktion in allen methoden integriert und ergebniss...
main: führt run_one für 4 beispielfunktionen aus
main: führt run_one für 4 beispielfunktione...
gibt pointer f_quad über
gibt pointer f_quad über
gibt ergebnis von f_quad zurück
gibt ergebnis von...
Endergebnis
float *out
Endergebnis...
\ No newline at end of file