diff --git a/ws2019/ipi/uebungen/ipi4.pdf b/ws2019/ipi/uebungen/ipi4.pdf new file mode 100644 index 0000000..15028fa Binary files /dev/null and b/ws2019/ipi/uebungen/ipi4.pdf differ diff --git a/ws2019/ipi/uebungen/ipi4.tex b/ws2019/ipi/uebungen/ipi4.tex new file mode 100644 index 0000000..f87c017 --- /dev/null +++ b/ws2019/ipi/uebungen/ipi4.tex @@ -0,0 +1,120 @@ +\documentclass[uebung]{../../../lecture} + +\usepackage{listings} +\usepackage{enumerate} +\usepackage{array} + +\lstset{ + frame=tb, + tabsize=4 +} + +\title{Übungsblatt Nr. 4} +\author{Samuel Weidemeier, Christian Merten} + +\begin{document} + +\begin{tabular}{|c|m{1cm}|m{1cm}|m{1cm}|m{1cm}|m{1cm}|@{}m{0cm}@{}} + \hline + Aufgabe & \centering A1 & \centering A2 & \centering A3 & \centering A4 & \centering $\sum$ & \\[5mm] \hline + Punkte & & & & & & \\[5mm] \hline +\end{tabular} + +\begin{aufgabe} + Zahlendarstellung + + \begin{enumerate}[a)] + \item Berechnung der Determinante einer $2\times 2 $ Matrix. + \begin{lstlisting}[language=C++, title=Berechnung der Determinante, captionpos=b] +double determinante_double(double a, double b, double c, double d) { + return a*d - b*c; +} + +float determinante(float a, float b, float c, float d) { + return a*d - b*c; +} + \end{lstlisting} + + Das Ergebnis bei Verwendung von \verb+float+ ist $10000$ und damit nicht exakt. + Das liegt an der zu geringen Größe eines \verb+float+'s, der nur rund $7$ Dezimalstellen exakt + speichern kann, danach wird gerundet. Das führt in diesem Fall zum Verlust aller + Nachkommastellen. Bei Verwendung des Datentyps \verb+double+ reichen die rund $16$ Stellen aus, um + das Ergebnis exakt darzustellen. + \item Assoziativität bei \verb+float+s + \begin{lstlisting}[language=C++, title=Vergleich der zwei Versionen, captionpos=b] +float testAssoziativitaet() { + for (int n = 6; n <= 14; n++) { + // (a+b)+c + float vers1 = (pow(10, n) + pow(-10, n)) + pow(10,-n); + // a+(b+c) + float vers2 = pow(10, n) + (pow(-10, n) + pow(10,-n)); + print(n, vers1, vers2, 0); + } +} + \end{lstlisting} + + Das Ergebnis ist bereits ab $n = 5$ nicht mehr assoziativ. Das liegt daran, dass + bei $(a+b)+c$ zunächst $10^{n} - 10^{n}$ berechnet wird, das aber immer null ist und danach + einfach $10^{-n}$ ausgewertet wird. Dabei kann die gesamte Präzision des \verb+float+'s + für die Nachkommastellen von $10^{-n}$ verwendet werden. Bei $a + (b+c)$ wird erst + $-10^{n} + 10^{-n}$ berechnet. Hierbei reicht die Präzision nicht aus, um die Nachkommastellen + darzustellen, da jetzt die Zahl bereits vor dem Komma sehr groß ist. Dadurch wird + $-10^{n} + 10^{-n}$ auf $-10^{n}$ gerundet und dann mit $10^{n}$ addiert, was dann null ergibt. + \end{enumerate} +\end{aufgabe} + +\begin{aufgabe} Effektiver Zinssatz + + Programm siehe \verb+uebung4.cpp+ + + Die Ergebnisse erleiden durch Runden und den begrenzten Speicherplatz des \verb+float+'s einige + Ungenauigkeiten. Die Differenz zum Grenzwert wird wie erwartet immer geringer. + + Die Genauigkeit der \verb+double+ Werte ist höher. +\end{aufgabe} + +\begin{aufgabe} Multiplikation im Zweierkomplement + + Zeigen Sie, dass für $n \in \N$ mit + \[ + a, b, a \cdot b \in \left[ -2^{n-1}, 2^{n-1}- 1 \right] + .\] für die Multiplikation im Zweierkomplement folgendes gilt: + \[ + d_n(a\cdot b) = s_n(d_n(a)\cdot d_n(b)) + .\] + + \begin{proof} + Seien $a, b \in \left[ -2^{n-1}, 2^{n-1}-1 \right] $ mit $-2^{n-1} \le a\cdot b \le 2^{n-1}-1$ beliebig. + + Fallunterscheidung: + \begin{enumerate}[(i)] + \item $a, b \ge 0$. Dann ist $a \cdot b \ge 0$. Damit + \[ + s_n(d_n(a)\cdot d_n(b)) = s_n(a\cdot b) = a\cdot b = d_n(a\cdot b) + .\] + \item $a < 0, b > 0$ (analog $a > 0, b <0)$. Dann ist $a \cdot b < 0$. + \begin{align*} + s_n(d_n(a)\cdot d_n(b)) &= s_n((2^{n} - |a|) \cdot b) \\ + &= s_n((2^{n} + a) \cdot b) \\ + &= s_n(2^{n} \cdot b + a\cdot b) \\ + &= s_n(2^{n} \cdot b - |a+b|) \\ + &= 2^{n} - |a+b| \\ + &= d_n(a\cdot b) + .\end{align*} + \item $a < 0, b < 0$. Dann ist $a \cdot b > 0$. + \begin{align*} + s_n(d_n(a)\cdot d_n(b)) &= s_n((2^{n} - |a|)(2^{n} - |b|) \\ + &= s_n((2^{n} \cdot 2^{n} + 2^{n} \cdot b + a\cdot 2^{n} + a\cdot b) \\ + &= a \cdot b \\ + &= d_n(a\cdot b) + .\end{align*} + \item $a < 0, b = 0$ (analog $a = 0, b < 0$). Dann ist $a \cdot b = 0$. + \begin{align*} + s_n(d_n(a) \cdot d_n(b)) = s_n(\left( 2^{n} - |a| \right) \cdot 0) = s_n(0) = 0 = d_n(0) = d_n(a\cdot b) + .\end{align*} + \end{enumerate} + \end{proof} + +\end{aufgabe} + +\end{document} diff --git a/ws2019/ipi/uebungen/uebung4.cpp b/ws2019/ipi/uebungen/uebung4.cpp new file mode 100644 index 0000000..c4699b8 --- /dev/null +++ b/ws2019/ipi/uebungen/uebung4.cpp @@ -0,0 +1,70 @@ +#include "cpp_headers/fcpp.hh" + +// Berechne die Determinante einer 2x2 Matrix mit doubles +double determinante_double(double a, double b, double c, double d) { + return a*d - b*c; +} + +// Berechne die Determinante einer 2x2 Matrix mit floats +float determinante(float a, float b, float c, float d) { + return a*d - b*c; +} + +// Teste die Assoziativitaet von floating point Zahlen +float testAssoziativitaet() { + for (int n = 1; n <= 14; n++) { + // (a+b)+c + float vers1 = (pow(10, n) + -pow(10, n)) + pow(10,-n); + // a+(b+c) + float vers2 = pow(10, n) + (-pow(10, n) + pow(10,-n)); + print(n, vers1, vers2, 0); + } +} + +// Berechnet den effektiven Zinssatz mit floats +// z: Zinssatz, n: Abrechnungsvorgaenge +float zins(float z, int n) { + return pow(1 + z/n, n) - 1; +} + +// Berechnet den effektiven Zinssatz mit doubles +// z: Zinssatz, n: Abrechnungsvorgaenge +double zins(double z, int n) { + return pow(1 + z/n, n) - 1; +} + +// Vergleiche die Berechnung des effektiven Zinssatzes bei n Abrechnungsvorgaengen +// mit floats und doubles und vergleiche mit dem Grenzwert für n -> unendlich. +void compare(int n) { + // Berechne effektiven Zins mit float + float zf = zins(0.06, n); + // Berechne die Differenz zu exp(z) - 1 + float difff = exp(0.06) - 1 - zf; + // Berechne effektiven Zins mit double + double zd = zins(0.06, n); + // Berechne die Differenz zu exp(z) - 1 + double diffd = exp(0.06) - 1 - zd; + // Gebe alles aus + print("Abrechnungsvorgaenge:", n, 0); + print("Zinssatz (float):", zf, 0); + print("Abweichung von exp(z) - 1:", difff, 0); + print("Zinssatz (double):", zd, 0); + print("Abweichung von exp(z) - 1:", diffd, 0); + print(""); +} + +int main() { + print("det", determinante(100, 0.01, -0.01, 100), 0); + print("double det", determinante_double(100, 0.01, -0.01, 100), 0); + testAssoziativitaet(); + + // vergleiche fuer verschiedene Werte + compare(1); + compare(4); + compare(12); + compare(365); + compare(365*24); + compare(365*24*60); + compare(365*24*60*2); + compare(365*24*60*60); +}