diff --git a/ws2019/ipi/uebungen/integration.cc b/ws2019/ipi/uebungen/integration.cc new file mode 100644 index 0000000..b72fff2 --- /dev/null +++ b/ws2019/ipi/uebungen/integration.cc @@ -0,0 +1,35 @@ +#include +#include + +// Implementiert die Trapezregel mit der Intervallanzahl n +// der unteren Integrationsgrenze a, der oberen Integrationsgrenze b +// und ueber die Funktion f +template +double trapezregel(int n, double a, double b, Function f) { + double h = (b-a)/n; // berechne intervalllaenge + double accum = 0; + for (int i = 1; i < n; i++) { + accum += f(a + i*h); // fuehre die summe aus + } + return h/2 * (f(a) + 2*accum + f(b)); // wende formel an +} + +// beispiel fuer funktor +class Wurzel { + public: + double operator()(double x) { + return std::sqrt(x); + } +}; + +int main() { + Wurzel f; + // fuehre integration fuer verschiedene Intervallanzahlen n aus + double integ10 = trapezregel(10, 0, 1.5, f); + double integ100 = trapezregel(100, 0, 1.5, f); + double integ1000 = trapezregel(1000, 0, 1.5, f); + std::cout << "Integral ueber sqrt(x) von 0 bis 1.5" << std::endl; + std::cout << "n = 10: " << integ10 << std::endl; + std::cout << "n = 100: " << integ100 << std::endl; + std::cout << "n = 1000: " << integ1000 << std::endl; +} diff --git a/ws2019/ipi/uebungen/ipi11.pdf b/ws2019/ipi/uebungen/ipi11.pdf new file mode 100644 index 0000000..4d7f00f Binary files /dev/null and b/ws2019/ipi/uebungen/ipi11.pdf differ diff --git a/ws2019/ipi/uebungen/ipi11.tex b/ws2019/ipi/uebungen/ipi11.tex new file mode 100644 index 0000000..4fcd1d8 --- /dev/null +++ b/ws2019/ipi/uebungen/ipi11.tex @@ -0,0 +1,331 @@ +\documentclass[uebung]{../../../lecture} + +\title{IPI: Übungsblatt 11} +\author{Samuel Weidemaier, Christian Merten} + +\begin{document} + +\begin{tabular}{|c|m{1cm}|m{1cm}|m{1cm}|m{1cm}|@{}m{0cm}@{}} + \hline + Aufgabe & \centering A1 & \centering A2 & \centering A3 & \centering $\sum$ & \\[5mm] \hline + Punkte & & & & & \\[5mm] \hline +\end{tabular} + +\begin{aufgabe} + Polynomschablone. Die vorgegebene Implementation der \lstinline{SimpleArray} Klasse + ist in \textit{simplearray.cc} zu finden. In \textit{polynomial.cc} befindet + sich die Implementation der verallgemeinerten \lstinline{Polynomial} Klasse. + \begin{lstlisting}[language=C++, captionpos=b, title=polynomial.cc] +#include +#include +#include "simplearray.cc" + +template +class Polynomial: public SimpleArray { + public: + // konstruiere Polynom vom Grad n + Polynomial (int n); + + // Default-Destruktor ist ok + // Default-Copy-Konstruktor ist ok + // Default-Zuweisung ist ok + + // Grad des Polynoms + int degree(); + + // Auswertung + T eval (T x); + + // Addition von Polynomen + Polynomial operator+ (Polynomial q); + + // Multiplikation von Polynomen + Polynomial operator* (Polynomial q); + + // Gleichheit + bool operator== (Polynomial q); + + // drucke Polynom + void print (); +}; + +// Constructor +template +Polynomial::Polynomial(int n) + : SimpleArray::SimpleArray(n+1,0.0) {} + +// Grad auswerten +template +int Polynomial::degree () +{ + return SimpleArray::maxIndex(); +} + +// Addition von Polynomen +template +Polynomial Polynomial::operator+ (Polynomial q) { + int nr=degree(); // mein grad + + if (q.degree()>nr) nr=q.degree(); + + Polynomial r(nr); // Ergebnispolynom + + for (int i=0; i<=nr; i=i+1) + { + if (i<=degree()) + r[i] = r[i]+(*this)[i]; // add me to r + if (i<=q.degree()) + r[i] = r[i]+q[i]; // add q to r + } + + return r; +} + +// Multiplikation von Polynomen +template +Polynomial Polynomial::operator* (Polynomial q) +{ + Polynomial r(degree()+q.degree()); // Ergebnispolynom + + for (int i=0; i<=degree(); i=i+1) + for (int j=0; j<=q.degree(); j=j+1) + r[i+j] = r[i+j] + (*this)[i]*q[j]; + + return r; +} + +// Drucken +template +void Polynomial::print () +{ + if (degree()<0) + std::cout << 0; + else + std::cout << (*this)[0]; + + for (int i=1; i<=SimpleArray::maxIndex(); i=i+1) + std::cout << " + " << (*this)[i] << "*x^" << i; + + std::cout << std::endl; +} + +int main() { + Polynomial p(2); + p[0] = 1.0; + p[1] = 1.0; + p.print(); + + p = p*p; + p.print(); + + Polynomial q(3); + q[0] = 2.0; + q[1] = -1.0; + q[3] = 4.0; + q.print(); +}\end{lstlisting} +\end{aufgabe} + +\begin{aufgabe} + Vektorimplementation + \begin{lstlisting}[language=C++, captionpos=b, title=vectors.cc] +#include +#include +#include +#include + +// a class implementing a mathematical vector +template +class Vector { + public: + // constructor, initializes vector with zeroes of length N + Vector() : _vector(N, 0) {} + // initialize by passing vector vec to initialize the vector object with + Vector(std::vector vec) { _vector = vec; } + + // copy constructor, assignment, destructor not needed + // all handled by std::vector + + // reference [] operator, used for assignments + K& operator[](int i) { + return _vector[i]; + } + + // const ref [] operator + K operator[](int i) const { + return _vector[i]; + } + + // return an iterator pointing to the first element of the underlying std::vector + typename std::vector::const_iterator begin() const { + return _vector.begin(); + } + + // return an iterator pointing to the last element of the underlying std::vector + typename std::vector::const_iterator end() const { + return _vector.end(); + } + + // dot product of two vectors of the same length + template + K operator*(const Vector& y) { + std::vector result(N); // new empty std::vector of correct size + // now multiply one element of the first with one of the second vector + std::transform(_vector.begin(), _vector.end(), y.begin(), result.begin(), std::multiplies()); + // and sum up the products + return std::accumulate(result.begin(), result.end(), 0); + } + + // vector addition + template + Vector operator+(const Vector& y) { + std::vector result(N); // new empty std::vector of correct size + // add elements by adding one element of the first to one of the second vector + std::transform(_vector.begin(), _vector.end(), y.begin(), result.begin(), std::plus()); + return Vector(result); + } + + // return the maximum value in the vector + K max() { + return *std::max_element(_vector.begin(), _vector.end()); + } + + // return the minimum value in the vector + K min() { + return *std::min_element(_vector.begin(), _vector.end()); + } + + // return the average value of the vector + K average() { + // sum up all elements + K sum = std::accumulate(_vector.begin(), _vector.end(), 0); + return sum / N; // and divide by length + } + + // run the specified function on each vector element + template + Vector map(F op) const { + std::vector result(N); // initialize new std::vector of correct size + // run op on each element + std::transform(_vector.begin(), _vector.end(), result.begin(), op); + return Vector(result); + } + private: + std::vector _vector; // the private std::vector container +}; + +// print vector +template +std::ostream& operator<<(std::ostream& os, const Vector& v) { + os << "["; // opening brackets + for (size_t i = 0; i < N; i++) { + os << v[i]; // print element + if(i < N-1) { + os << ", "; // if not the last one, add comma + } + } + os << "]"; // closing brackets + return os; +} + +// scalar multiplication for vector * scalar +template +Vector operator*(const Vector& v, const K2 k) { + // multiply a scalar value using the generic map function + return v.map(std::bind1st(std::multiplies(), k)); +} + +// scalar multiplication for scalar * vector +template +Vector operator*(const K2 k, const Vector& v) { + return v * k; +} + + +// example function +double foo(double val) { + return val*2+3; +} + +// testing out functionalities +int main() { + Vector a; + Vector b; + a[0] = 0; + a[1] = 0; + a[2] = 4; + + b[0] = 42; + b[1] = -20; + b[2] = 3; + + std::cout << "Vektor a: " << a << ", Vektor b: " << b << std::endl; + std::cout << "a+b: " << a+b << std::endl; + std::cout << "a*b: " << a*b << std::endl; + std::cout << "42*b: " << 42*b << std::endl; + std::cout << "b*42: " << b*42 << std::endl; + std::cout << "max(a): " << a.max() << std::endl; + std::cout << "min(a): " << a.min() << std::endl; + std::cout << "mean(a): " << a.average() << std::endl; + std::cout << "foo angewendet auf b: " << b.map(foo) << std::endl; +}\end{lstlisting} +\end{aufgabe} + +\begin{aufgabe}[Funktoren und statischer Polymorphismus] + \begin{enumerate}[(a)] + \item Integration mittels Trapezregel + für $n = 10$, $n = 100$ und $n = 1000$ beispielsweise ausgerechnet. +\begin{lstlisting}[language=C++, captionpos=b, title=integration.cc] +#include +#include + +// Implementiert die Trapezregel mit der Intervallanzahl n +// der unteren Integrationsgrenze a, der oberen Integrationsgrenze b +// und ueber die Funktion f +template +double trapezregel(int n, double a, double b, Function f) { + double h = (b-a)/n; // berechne intervalllaenge + double accum = 0; + for (int i = 1; i < n; i++) { + accum += f(a + i*h); // fuehre die summe aus + } + return h/2 * (f(a) + 2*accum + f(b)); // wende formel an +} + +// beispiel fuer funktor +class Wurzel { + public: + double operator()(double x) { + return std::sqrt(x); + } +}; + +int main() { + Wurzel f; + // fuehre integration fuer verschiedene Intervallanzahlen n aus + double integ10 = trapezregel(10, 0, 1.5, f); + double integ100 = trapezregel(100, 0, 1.5, f); + double integ1000 = trapezregel(1000, 0, 1.5, f); + std::cout << "Integral ueber sqrt(x) von 0 bis 1.5" << std::endl; + std::cout << "n = 10: " << integ10 << std::endl; + std::cout << "n = 100: " << integ100 << std::endl; + std::cout << "n = 1000: " << integ1000 << std::endl; +}\end{lstlisting} + + \item Vorteile der Verwendung von statischem Polymorphismus gegenüber dynamischem Polymorphismus: + \begin{itemize} + \item Auswertung zum Zeitpunkt des Kompilierens führt zu besserer Optimierung und + Fehlererkennung durch den Compiler. + \item Weniger Overhead durch VTABLE's, etc. + \item Deshalb effizienter und schneller + \end{itemize} + Nachteile: + \begin{itemize} + \item Potentiell unübersichtlicher + \item Größe der Programme als kompilierte Binärdatei ist größer + \end{itemize} + + \end{enumerate} +\end{aufgabe} + +\end{document} diff --git a/ws2019/ipi/uebungen/vectors.cc b/ws2019/ipi/uebungen/vectors.cc index 7992b64..bf2f35c 100644 --- a/ws2019/ipi/uebungen/vectors.cc +++ b/ws2019/ipi/uebungen/vectors.cc @@ -97,7 +97,7 @@ std::ostream& operator<<(std::ostream& os, const Vector& v) { return os; } -// scalar multiplication +// scalar multiplication for vector * scalar template Vector operator*(const Vector& v, const K2 k) { // multiply a scalar value using the generic map function