diff --git a/20181119/hp-musterloesung-20181119.tex b/20181119/hp-musterloesung-20181119.tex index 4e44498e8dd279111dfb34bfeb949e9753e03eb3..dff2f028b51825a80b4b390f6c7a2dc227a9c907 100644 --- a/20181119/hp-musterloesung-20181119.tex +++ b/20181119/hp-musterloesung-20181119.tex @@ -1,5 +1,5 @@ -% hp-musterloesung-20181112.pdf - Solutions to the Exercises on Low-Level Programming / Applied Computer Sciences -% Copyright (C) 2013, 2015, 2016, 2017, 2018 Peter Gerwinski +% hp-musterloesung-20181119.pdf - Solutions to the Exercises on Low-Level Programming / Applied Computer Sciences +% Copyright (C) 2013, 2015, 2016, 2017, 2018, 2019 Peter Gerwinski % % This document is free software: you can redistribute it and/or % modify it either under the terms of the Creative Commons diff --git a/20181126/hp-musterloesung-20181126.tex b/20181126/hp-musterloesung-20181126.tex index af48f54a7d95305af2327f19875ae154accce80e..5278288de1979f7b048bf672668fbcecd49a96ac 100644 --- a/20181126/hp-musterloesung-20181126.tex +++ b/20181126/hp-musterloesung-20181126.tex @@ -1,5 +1,5 @@ -% hp-musterloesung-20181112.pdf - Solutions to the Exercises on Low-Level Programming / Applied Computer Sciences -% Copyright (C) 2013, 2015, 2016, 2017, 2018 Peter Gerwinski +% hp-musterloesung-20181126.pdf - Solutions to the Exercises on Low-Level Programming / Applied Computer Sciences +% Copyright (C) 2013, 2015, 2016, 2017, 2018, 2019 Peter Gerwinski % % This document is free software: you can redistribute it and/or % modify it either under the terms of the Creative Commons diff --git a/20181203/hp-musterloesung-20181203.pdf b/20181203/hp-musterloesung-20181203.pdf new file mode 100644 index 0000000000000000000000000000000000000000..c04ed216c89605746bacccae02999f4d865577d0 Binary files /dev/null and b/20181203/hp-musterloesung-20181203.pdf differ diff --git a/20181203/hp-musterloesung-20181203.tex b/20181203/hp-musterloesung-20181203.tex new file mode 100644 index 0000000000000000000000000000000000000000..a17574ca126ab20a36cfe7394521affc53c61010 --- /dev/null +++ b/20181203/hp-musterloesung-20181203.tex @@ -0,0 +1,275 @@ +% hp-musterloesung-20181203.pdf - Solutions to the Exercises on Low-Level Programming / Applied Computer Sciences +% Copyright (C) 2013, 2015, 2016, 2017, 2018, 2019 Peter Gerwinski +% +% This document is free software: you can redistribute it and/or +% modify it either under the terms of the Creative Commons +% Attribution-ShareAlike 3.0 License, or under the terms of the +% GNU General Public License as published by the Free Software +% Foundation, either version 3 of the License, or (at your option) +% any later version. +% +% This document is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this document. If not, see <http://www.gnu.org/licenses/>. +% +% You should have received a copy of the Creative Commons +% Attribution-ShareAlike 3.0 Unported License along with this +% document. If not, see <http://creativecommons.org/licenses/>. + +% README: XBM-Grafik, LED-Blinkmuster + +\documentclass[a4paper]{article} + +\usepackage{pgscript} +\usepackage{sfmath} + +\begin{document} + + \section*{Hardwarenahe Programmierung\\ + Musterlösung zu den Übungsaufgaben -- 3.\ Dezember 2018} + + \exercise{XBM-Grafik} + + Bei einer XBM-Grafikdatei handelt es sich + um ein als C-Quelltext abgespeichertes Array, + das die Bildinformationen enthält: + \begin{itemize}\itemsep0pt + \item Jedes Bit entspricht einem Pixel. + \item Nullen stehen für Weiß, Einsen für Schwarz. + \item Das Bit mit Zahlenwert 1 steht für einen Bildpunkt ganz links im Byte, + das Bit mit Zahlenwert 128 für einen Bildpunkt ganz rechts. + (Diese Bit-Reihenfolge heißt \newterm{LSB first}.) + \item Jede Zeile des Bildes wird auf ganze Bytes aufgefüllt. + \item Breite und Höhe des Bildes sind als Konstantendefinitionen + (\lstinline{#define}) in der Datei enthalten. + \end{itemize} + Sie können eine XBM-Datei sowohl mit einem Texteditor + als auch mit vielen Grafikprogrammen öffnen und bearbeiten. + + Beispiel (\gitfile{hp}{20181203}{aufgabe-1.xbm}):\hfill + \makebox(0,0)[tr]{\framebox{\includegraphics[scale=3]{aufgabe-1.png}}} + \begin{lstlisting} + #define aufgabe_1_width 14 + #define aufgabe_1_height 14 + static unsigned char aufgabe_1_bits[] = { + 0x00, 0x00, 0xf0, 0x03, 0x08, 0x04, 0x04, 0x08, 0x02, 0x10, 0x32, 0x13, + 0x22, 0x12, 0x02, 0x10, 0x0a, 0x14, 0x12, 0x12, 0xe4, 0x09, 0x08, 0x04, + 0xf0, 0x03, 0x00, 0x00 }; + \end{lstlisting} + Ein C-Programm, das eine XBM-Grafik nutzen will, + kann die \file{.xbm}-Datei mit \lstinline{#include "..."} direkt einbinden. + + Schreiben Sie ein Programm, das die XBM-Datei als ASCII-Grafik ausgibt, z.\,B.: + \begin{lstlisting}[style=terminal,lineskip=-4pt] + + ****** + * * + * * + * * + * ** ** * + * * * * + * * + * * * * + * * * * + * **** * + * * + ****** + ¡ ¿ + \end{lstlisting} + \points{8} + + (Hinweis für die Klausur: Abgabe auf Datenträger ist erlaubt und erwünscht, + aber nicht zwingend.) + + \solution + + Siehe die Datei \gitfile{hp}{20181203}{loesung-1.c}. + + Der Ausdruck \lstinline{(aufgabe_3_width + 7) / 8} + ist die auf ganze Bytes aufgerundete Breits des Bildes in Bytes. + Ohne das "`\lstinline{+ 7}"' in der Klammer würde stets abgerundet; + die Breite von Bildern, deren Breite kein Vielfaches von 8 ist, + wäre dann immer um 1 zu klein. + Dadurch daß wir $n - 1$ addieren, bevor wir durch $n$ dividieren, + machen wir aus dem Abrunden ein Aufrunden. + + In jedem Durchlauf der äußeren Schleife + wird der Zeiger \lstinline{p} auf den Anfang der Zeile \lstinline{i} des Bildes gesetzt. + + Innerhalb der Zeile gehen wir mit einer Bit-Maske \lstinline{mask} + die Bits innerhalb des Bytes \lstinline{*p} von rechts nach links durch (LSB first). + Wenn das Bit aus der Maske links herausgeschoben wird, + setzen wir die Maske auf \lstinline{0x01} zurück + und setzen den Zeiger \lstinline{p} auf das nächste Byte. + + (Der Datentyp \lstinline{unsigned char} + ist eine vorzeichenlose ganze Zahl von der Größe einer Speicherzelle + und normalerweise identisch mit \lstinline{uint8_t}. + Da das XBM-Dateiformat den Datentyp \lstinline{unsigned char} verwendet, + geschieht dies auch im Programm \gitfile{hp}{20181203}{loesung-1.c}; + ansonsten wäre \lstinline{uint8_t} eine bessere Wahl.) + + \exercise{LED-Blinkmuster} + + Wir betrachten das folgende Programm für einen ATmega32-Mikro-Controller + (Datei: \gitfile{hp}{20180108}{aufgabe-2.c}). + + \begin{minipage}[t]{7cm} + \begin{lstlisting}[gobble=6] + #include <stdint.h> + #include <avr/io.h> + #include <avr/interrupt.h> + + uint8_t counter = 1; + uint8_t leds = 0; + + ISR (TIMER0_COMP_vect) + { + if (counter == 0) + { + leds = (leds + 1) % 8; + PORTC = leds << 4; + } + counter++; + } + \end{lstlisting} + \end{minipage}\hfill\begin{minipage}[t]{8.5cm} + \begin{lstlisting}[gobble=6] + void init (void) + { + cli (); + TCCR0 = (1 << CS01) | (1 << CS00); + TIMSK = 1 << OCIE0; + sei (); + DDRC = 0x70; + } + + int main (void) + { + init (); + while (1) + ; /* do nothing */ + return 0; + } + \end{lstlisting} + \end{minipage} + + An die Bits Nr.\ 4, 5 und 6 des Output-Ports C des Mikro-Controllers sind LEDs angeschlossen.\\ + Sobald das Programm läuft, blinken diese in charakteristischer Weise: + \begin{quote} + \newcommand{\tdn}[1]{\raisebox{-2pt}{#1}} + \begin{tabular}{|c|c|c|c|}\hline + \tdn{Phase} & \tdn{LED oben (rot)} & \tdn{LED Mitte (gelb)} & \tdn{LED unten (grün)} \\[2pt]\hline + 1 & aus & aus & an \\\hline + 2 & aus & an & aus \\\hline + 3 & aus & an & an \\\hline + 4 & an & aus & aus \\\hline + 5 & an & aus & an \\\hline + 6 & an & an & aus \\\hline + 7 & an & an & an \\\hline + 8 & aus & aus & aus \\\hline + \end{tabular} + \end{quote} + % 8000000 / 64 = 125000 + % 8000000 / 64 / 256 = 488.28125 + % 8000000 / 64 / 256 / 256 = 1.9073486328125 + Jede Phase dauert etwas länger als eine halbe Sekunde. + Nach 8 Phasen wiederholt sich das Schema. + + Erklären Sie das Verhalten des Programms anhand des Quelltextes: + \vspace{-\medskipamount} + \begin{itemize}\itemsep0pt + \item[(a)] + Wieso macht das Programm überhaupt etwas, + wenn doch das Hauptprogramm nach dem Initialisieren lediglich eine Endlosschleife ausführt, + in der \emph{nichts} passiert? + \points{1} + \item[(b)] + Wieso wird die Zeile \lstinline|PORTC = leds << 4;| überhaupt aufgerufen, + wenn dies doch nur unter der Bedingung \lstinline|counter == 0| passiert, + wobei die Variable \lstinline|counter| auf 1 initialisiert, + fortwährend erhöht und nirgendwo zurückgesetzt wird? + \points{2} + \item[(c)] + Wie kommt das oben beschriebene Blinkmuster zustande? + \points{2} + \item[(d)] + Wieso dauert eine Phase ungefähr eine halbe Sekunde? + \points{2} + \item[(e)] + Was bedeutet "`\lstinline|ISR (TIMER0_COMP_vect)|"'? + \points{1} + \end{itemize} + + Hinweis: + \vspace{-\medskipamount} + \begin{itemize}\itemsep0pt + \item + Die Funktion \lstinline|init()| sorgt dafür, daß der Timer-Interrupt Nr.\ 0 des Mikro-Controllers + etwa 488mal pro Sekunde aufgerufen wird. + Außerdem % schaltet sie eventuell an Port B angeschlossene weitere LEDs aus und + initialisiert sie die benötigten Bits an Port C als Output-Ports. + Sie selbst brauchen die Funktion \lstinline|init()| nicht weiter zu erklären. +% \item +% Während der Übung können Sie sich das Verhalten des Programms +% an einem RP6-Roboter vorführen lassen. + \end{itemize} + + \clearpage + \solution + + \begin{itemize}\itemsep0pt + \item[(a)] + \textbf{Wieso macht das Programm überhaupt etwas, + wenn doch das Hauptprogramm nach dem Initialisieren lediglich eine Endlosschleife ausführt, + in der \emph{nichts} passiert?} + + Das Blinken wird durch einen Interrupt-Handler implementiert. + Dieser wird nicht durch das Hauptprogramm, + sondern durch ein Hardware-Ereignis (hier: Uhr) aufgerufen. + + \item[(b)] + \textbf{Wieso wird die Zeile \lstinline|PORTC = leds << 4;| überhaupt aufgerufen, + wenn dies doch nur unter der Bedingung \lstinline|counter == 0| passiert, + wobei die Variable \lstinline|counter| auf 1 initialisiert, + fortwährend erhöht und nirgendwo zurückgesetzt wird?} + + Die vorzeichenlose 8-Bit-Variable \lstinline{counter} kann nur + Werte von 0 bis 255 annehmen; bei einem weiteren + INkrementieren springt sie wieder auf 0 (Überlauf), + und die \lstinline{if}-Bedingung ist erfüllt. + + \item[(c)] + \textbf{Wie kommt das oben beschriebene Blinkmuster zustande?} + + In jedem Aufruf des Interrupt-Handlers wird die Variable + \lstinline{leds} um 1 erhöht und anschließend modulo 8 genommen. + Sie durchläuft daher immer wieder die Zahlen von 0 bis 7. + + Durch die Schiebeoperation \lstinline{leds << 4} werden die 3 Bits + der Variablen \lstinline{leds} an diejenigen Stellen im Byte + geschoben, an denen die LEDs an den Mikro-Controller + angeschlossen sind (Bits 4, 5 und 6). + + Entsprechend durchläuft das Blinkmuster immer wieder + die Binärdarstellungen der Zahlen von 0 bis 7 + (genauer: von 1 bis 7 und danach 0). + + \item[(d)] + \textbf{Wieso dauert eine Phase ungefähr eine halbe Sekunde?} + + Der Interrupt-Handler wird gemäß Hinweis 488mal pro Sekunde aufgerufen. + Bei jedem 256sten Aufruf ändert sich das LED-Muster. + Eine Phase dauert somit $\frac{256}{488} \approx 0.52$ Sekunden. + + \item[(e)] + \textbf{Was bedeutet "`\lstinline|ISR (TIMER0_COMP_vect)|"'?} + + Deklaration eines Interrupt-Handlers für den Timer-Interrupt Nr.\ 0 + \end{itemize} + +\end{document} diff --git a/20181210/hp-musterloesung-20181210.pdf b/20181210/hp-musterloesung-20181210.pdf new file mode 100644 index 0000000000000000000000000000000000000000..e49a72d2b2e879886e1d051d00b6ccc3e1790800 Binary files /dev/null and b/20181210/hp-musterloesung-20181210.pdf differ diff --git a/20181210/hp-musterloesung-20181210.tex b/20181210/hp-musterloesung-20181210.tex new file mode 100644 index 0000000000000000000000000000000000000000..655b9be4345ea22435674ca06a841701dca0773e --- /dev/null +++ b/20181210/hp-musterloesung-20181210.tex @@ -0,0 +1,266 @@ +% hp-musterloesung-20181210.pdf - Solutions to the Exercises on Low-Level Programming / Applied Computer Sciences +% Copyright (C) 2013, 2015, 2016, 2017, 2018, 2019 Peter Gerwinski +% +% This document is free software: you can redistribute it and/or +% modify it either under the terms of the Creative Commons +% Attribution-ShareAlike 3.0 License, or under the terms of the +% GNU General Public License as published by the Free Software +% Foundation, either version 3 of the License, or (at your option) +% any later version. +% +% This document is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this document. If not, see <http://www.gnu.org/licenses/>. +% +% You should have received a copy of the Creative Commons +% Attribution-ShareAlike 3.0 Unported License along with this +% document. If not, see <http://creativecommons.org/licenses/>. + +% README: Trickprogrammierung, Thermometer-Baustein an I²C-Bus + +\documentclass[a4paper]{article} + +\usepackage{pgscript} +\usepackage{gensymb} +\usepackage{sfmath} + +\newcommand{\ItwoC}{I\raisebox{0.5ex}{\footnotesize 2}C} +\newcommand{\ITWOC}{I\raisebox{0.5ex}{\normalsize 2}C} + +\begin{document} + + \section*{Hardwarenahe Programmierung\\ + Musterlösung zu den Übungsaufgaben -- 10.\ Dezember 2018} + + \exercise{Trickprogrammierung} + + Wir betrachten das folgende Programm (Datei: \gitfile{hp}{20181210}{aufgabe-1.c}): + \begin{lstlisting} + #include <stdio.h> + #include <stdint.h> + + int main (void) + { + uint64_t x = 4262939000843297096; + char *s = &x; + printf ("%s\n", s); + return 0; + } + \end{lstlisting} + Das Programm wird compiliert und auf einem 64-Bit-Little-Endian-Computer ausgeführt: + \begin{lstlisting}[style=terminal] + $ ¡gcc -Wall -O aufgabe-1.c -o aufgabe-1¿ + aufgabe-1.c: In function `main': + aufgabe-1.c:7:13: warning: initialization from incompatible pointer type [...] + $ ¡./aufgabe-1¿ + Hallo + \end{lstlisting} + + \begin{itemize} + \item[(a)] + Erklären Sie die Warnung beim Compilieren. \points{2} + \item[(b)] + Erklären Sie die Ausgabe des Programms. \points{5} + \item[(c)] + Wie würde die Ausgabe des Programms auf einem 64-Bit-Big-Endian-Computer lauten? \points{3} + \end{itemize} + Hinweis: Modifizieren Sie das Programm + und lassen Sie sich Speicherinhalte ausgeben. + + \solution + + \begin{itemize} + \item[(a)] + \textbf{Erklären Sie die Warnung beim Compilieren.} + + Zeile 7 des Programms enthält eine Zuweisung von \lstinline{&x} + an die Variable \lstinline{s}. + Der Ausdruck \lstinline{&x} steht für die Speicheradresse der Variablen \lstinline{x}, + ist also ein Zeiger auf \lstinline{x}, + also ein Zeiger auf eine \lstinline{uint64_t}. + Die Variable \lstinline{s} hingegen ist ein Zeiger auf \lstinline{char}, + also ein Zeiger auf eine viel kleinere Zahl, + also ein anderer Zeigertyp. + + \item[(b)] + \textbf{Erklären Sie die Ausgabe des Programms.} + + Die 64-Bit-Zahl (\lstinline{uint64_t}) \lstinline{x} + belegt 8 Speicherzellen (Bytes) von jeweils 8 Bit. + Um herauszufinden, was diese enthalten, + lassen wir uns \lstinline{x} als Hexadezimalzahl ausgeben, + z.\,B.\ mittels \lstinline{printf ("%lx\n", x)} + (auf 32-Bit-Rechnern: \lstinline{"%llx\n"}) + oder mittels \lstinline{printf ("%" PRIx64 "\n", x)} + (erfordert \lstinline{#include <inttypes.h>} + -- siehe die Datei \gitfile{hp}{20181210}{loesung-1-1.c}). + Das Ergebnis lautet: + \begin{lstlisting}[style=terminal,gobble=8] + 3b29006f6c6c6148 + \end{lstlisting} + Auf einzelne Bytes verteilt: + \begin{lstlisting}[style=terminal,gobble=8] + 3b 29 00 6f 6c 6c 61 48 + \end{lstlisting} + Auf einem Little-Endian-Rechner + ist die Reihenfolge der Bytes in den Speicherzellen genau umgekehrt: + \begin{lstlisting}[style=terminal,gobble=8] + 48 61 6c 6c 6f 00 29 3b + \end{lstlisting} + Wenn wir uns diese Bytes als Zeichen ausgeben lassen + (\lstinline{printf()} mit \lstinline{%c} -- siehe die Datei \gitfile{hp}{20181210}{loesung-1-2.c}), + erhalten wir: + \begin{lstlisting}[style=terminal,gobble=8] + H a l l o ) ; + \end{lstlisting} + Das Zeichen hinter "`Hallo"' ist ein Null-Symbol (Zahlenwert 0) + und wird von \lstinline{printf ("%s")} als Ende des Strings erkannt. + Damit ist die Ausgabe \lstinline[style=terminal]{Hallo} + des Programms erklärt. + + \goodbreak + \item[(c)] + \textbf{Wie würde die Ausgabe des Programms auf einem 64-Bit-Big-Endian-Computer lauten?} + + Auf einem Big-Endian-Computer (egal, wieviele Bits die Prozessorregister haben) + ist die Reihenfolge der Bytes in den Speicherzellen genau umgekehrt + wie auf einem Little-Endian-Computer, hier also: + \begin{lstlisting}[style=terminal,gobble=8] + 3b 29 00 6f 6c 6c 61 48 + \end{lstlisting} + \lstinline{printf ("%s")} gibt in diesem Fall die Hexadezimalzahlen + \lstinline[style=terminal]{3b} und \lstinline[style=terminal]{29} + als Zeichen aus. Danach steht das String-Ende-Symbol mit Zahlenwert 0, + und die Ausgabe bricht ab. + Da, wie oben ermittelt, die Hexadezimalzahl \lstinline[style=terminal]{3b} + für das Zeichen \lstinline[style=terminal]{;} + und \lstinline[style=terminal]{29} + für das Zeichen \lstinline[style=terminal]{)} steht, + lautet somit die Ausgabe: + \begin{lstlisting}[style=terminal,gobble=8] + ;) + \end{lstlisting} + Um die Aufgabe zu lösen, können Sie übrigens auch + auf einem Little-Endian-Computer (Standard-Notebook) + einen Big-Endian-Computer simulieren, + indem Sie die Reihenfolge der Bytes in der Zahl \lstinline{x} umdrehen + -- siehe die Datei \gitfile{hp}{20181210}{loesung-1-3.c}. + \end{itemize} + + \exercise{Thermometer-Baustein an \ITWOC-Bus} + + Eine Firma stellt einen elektronischen Thermometer-Baustein her, + den man über die serielle Schnittstelle (RS-232) an einen PC anschließen kann, + um die Temperatur auszulesen. + Nun wird eine Variante des Thermo"-meter-Bausteins entwickelt, + die die Temperatur zusätzlich über einen \ItwoC-Bus bereitstellt. + + Um das neue Thermometer zu testen, wird es in ein Gefäß mit heißem Wasser gelegt, + das langsam auf Zimmertemperatur abkühlt. + Alle 10 Minuten liest ein Programm, das auf dem PC läuft, + die gemessene Temperatur über beide Schnittstellen aus + und erzeugt daraus die folgende Tabelle: + + \begin{center} + \renewcommand{\arraystretch}{1.2} + \begin{tabular}{|c|c|c|}\hline + Zeit /\,min. & Temperatur per RS-232 /\,\degree C & Temperatur per \ItwoC\ /\,\degree C \\\hline\hline + \phantom{0}0 & 94 & 122 \\\hline + 10 & 47 & 244 \\\hline + 20 & 30 & 120 \\\hline + 30 & 24 & \phantom{0}24 \\\hline + 40 & 21 & 168 \\\hline + \end{tabular} + \end{center} + + \begin{itemize} + \item[(a)] + Aus dem Vergleich der Meßdaten läßt sich + auf einen Fehler bei der \ItwoC-Übertragung schließen.\\ + Um welchen Fehler handelt es sich, + und wie ergibt sich dies aus den Meßdaten? + \points{5} + \item[(b)] + Schreiben Sie eine C-Funktion \lstinline{uint8_t repair (uint8_t data)}, + die eine über den \ItwoC-Bus empfangene fehlerhafte Temperatur \lstinline{data} korrigiert. + \points{5} + \end{itemize} + + \solution + + \begin{itemize} + \item[(a)] + \textbf{Aus dem Vergleich der Meßdaten läßt sich + auf einen Fehler bei der \ItwoC-Übertragung schließen. + Um welchen Fehler handelt es sich, + und wie ergibt sich dies aus den Meßdaten?} + + Sowohl RS-232 als auch \ItwoC\ übertragen die Daten Bit für Bit. + Für die Fehlersuche ist es daher sinnvoll, + die Meßwerte als Binärzahlen zu betrachten: + + \begin{center} + \renewcommand{\arraystretch}{1.2} + \begin{tabular}{|c|c|c|}\hline + Zeit /\,min. & Temperatur per RS-232 /\,\degree C & Temperatur per \ItwoC\ /\,\degree C \\\hline\hline + \phantom{0}0 & 94$_{10}$ = 01011110$_2$ & 122$_{10}$ = 01111010$_2$ \\\hline + 10 & 47$_{10}$ = 00101111$_2$ & 244$_{10}$ = 11110100$_2$ \\\hline + 20 & 30$_{10}$ = 00011110$_2$ & 120$_{10}$ = 01111000$_2$ \\\hline + 30 & 24$_{10}$ = 00011000$_2$ & \phantom{0}24$_{10}$ = 00011000$_2$ \\\hline + 40 & 21$_{10}$ = 00010101$_2$ & 168$_{10}$ = 10101000$_2$ \\\hline + \end{tabular} + \end{center} + + Man erkennt, daß die Reihenfolge der Bits in den (fehlerhaften) \ItwoC-Meßwerten + genau die umgekehrte Reihenfolge der Bits in den (korrekten) RS-232-Mewßwerten ist. + Der Übertragungsfehler besteht also darin, + daß die Bits in der falschen Reihenfolge übertragen wurden. + + Dies paßt gut damit zusammen, + daß die Bit-Reihenfolge von \ItwoC\ \emph{MSB First}, die von RS-232 hingegen \emph{LSB First\/} ist. + Offenbar haben die Entwickler der \ItwoC-Schnittstelle dies übersehen + und die \ItwoC-Daten ebenfalls \emph{LSB First\/} übertragen. + + \goodbreak + \item[(b)] + \textbf{Schreiben Sie eine C-Funktion \lstinline{uint8_t repair (uint8_t data)}, + die eine über den \ItwoC-Bus empfangene fehlerhafte Temperatur \lstinline{data} korrigiert.} + + Die Aufgabe der Funktion besteht darin, + eine 8-Bit-Zahl \lstinline{data} entgegenzunehmen, + die Reihenfolge der 8 Bits genau umzudrehen + und das Ergebnis mittels \lstinline{return} zurückzugeben. + + Zu diesem Zweck gehen wir die 8 Bits in einer Schleife durch + -- siehe die Datei \gitfile{hp}{20181210}{loesung-2.c}. + Wir lassen eine Lese-Maske \lstinline{mask_data} von rechts nach links + und gleichzeitig eine Schreib-Maske \lstinline{mask_result} + von links nach rechts wandern. + Immer wenn die Lese-Maske in \lstinline{data} eine 1 findet, + schreibt die Schreib-Maske diese in die Ergebnisvariable \lstinline{result}. + + Da \lstinline{result} auf 0 initialisiert wurde, + brauchen wir Nullen nicht hineinzuschreiben. + Ansonsten wäre dies mit \lstinline{result &= ~mask_result} möglich. + + Um die Schleife bis 8 zählen zu lassen, + könnte man eine weitere Zähler-Variable von 0 bis 7 zählen lassen, + z.\,B.\ \lstinline{for (int i = 0; i < 8; i++)}. + Dies ist jedoch nicht nötig, wenn man beachtet, + daß die Masken den Wert 0 annehmen, + sobald das Bit aus der 8-Bit-Variablen herausgeschoben wurde. + In \gitfile{hp}{20181210}{loesung-2.c} wird \lstinline{mask_data} auf 0 geprüft; + genausogut könnte man auch \lstinline{mask_result} prüfen. + + Das \lstinline{return result} ist notwendig. + Eine Ausgabe des Ergebnisses per \lstinline{printf()} o.\,ä.\ + erfüllt \emph{nicht\/} die Aufgabenstellung. + (In \gitfile{hp}{20181210}{loesung-2.c} erfolgt entsprechend \lstinline{printf()} + nur im Testprogramm \lstinline{main()}.) + \end{itemize} + +\end{document} diff --git a/20181210/loesung-1-1.c b/20181210/loesung-1-1.c new file mode 100644 index 0000000000000000000000000000000000000000..26fcc817796b3da118b5dda92f45bfb870e315b6 --- /dev/null +++ b/20181210/loesung-1-1.c @@ -0,0 +1,13 @@ +#include <stdio.h> +#include <stdint.h> +#include <inttypes.h> + +int main (void) +{ + uint64_t x = 4262939000843297096; + char *s = &x; + printf ("%lx\n", x); + printf ("%" PRIx64 "\n", x); + printf ("%s\n", s); + return 0; +} diff --git a/20181210/loesung-1-2.c b/20181210/loesung-1-2.c new file mode 100644 index 0000000000000000000000000000000000000000..7151db69b2e675f17517d7b7c3814bbda3b1fa89 --- /dev/null +++ b/20181210/loesung-1-2.c @@ -0,0 +1,15 @@ +#include <stdio.h> +#include <stdint.h> +#include <inttypes.h> + +int main (void) +{ + uint64_t x = 4262939000843297096; + char *s = &x; + printf ("%lx\n", x); + printf ("%" PRIx64 "\n", x); + printf ("%c %c %c %c %c %c %c %c\n", + 0x48, 0x61, 0x6c, 0x6c, 0x6f, 0x00, 0x29, 0x3b); + printf ("%s\n", s); + return 0; +} diff --git a/20181210/loesung-1-3.c b/20181210/loesung-1-3.c new file mode 100644 index 0000000000000000000000000000000000000000..fadccdef1155e4d16b5da0c8a82d8e7ae76ca3cc --- /dev/null +++ b/20181210/loesung-1-3.c @@ -0,0 +1,11 @@ +#include <stdio.h> +#include <stdint.h> +#include <inttypes.h> + +int main (void) +{ + uint64_t x = 0x48616c6c6f00293b; + char *s = &x; + printf ("%s\n", s); + return 0; +} diff --git a/20181210/loesung-2.c b/20181210/loesung-2.c new file mode 100644 index 0000000000000000000000000000000000000000..b02d98b51b9bc525a567afea2f0dce5a8e6413a5 --- /dev/null +++ b/20181210/loesung-2.c @@ -0,0 +1,26 @@ +#include <stdio.h> +#include <stdint.h> + +uint8_t repair (uint8_t data) +{ + uint8_t result = 0; + uint8_t mask_data = 0x01; + uint8_t mask_result = 0x80; + while (mask_data) + { + if (data & mask_data) + result |= mask_result; + mask_data <<= 1; + mask_result >>= 1; + } + return result; +} + +int main (void) +{ + int data[] = { 122, 244, 120, 24, 168, -1 }; + int i = 0; + while (data[i] >= 0) + printf ("%d\n", repair (data[i++])); + return 0; +} diff --git a/20181217/hp-musterloesung-20181217.pdf b/20181217/hp-musterloesung-20181217.pdf new file mode 100644 index 0000000000000000000000000000000000000000..bd59e3f1d9892bb04c4d67e2f9a54ea764110632 Binary files /dev/null and b/20181217/hp-musterloesung-20181217.pdf differ diff --git a/20181217/hp-musterloesung-20181217.tex b/20181217/hp-musterloesung-20181217.tex new file mode 100644 index 0000000000000000000000000000000000000000..bda69709b736dbeb8a8a79cb05eef6aa00ac1af6 --- /dev/null +++ b/20181217/hp-musterloesung-20181217.tex @@ -0,0 +1,554 @@ +% hp-musterloesung-20181217.pdf - Solutions to the Exercises on Low-Level Programming / Applied Computer Sciences +% Copyright (C) 2013, 2015, 2016, 2017, 2018, 2019 Peter Gerwinski +% +% This document is free software: you can redistribute it and/or +% modify it either under the terms of the Creative Commons +% Attribution-ShareAlike 3.0 License, or under the terms of the +% GNU General Public License as published by the Free Software +% Foundation, either version 3 of the License, or (at your option) +% any later version. +% +% This document is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this document. If not, see <http://www.gnu.org/licenses/>. +% +% You should have received a copy of the Creative Commons +% Attribution-ShareAlike 3.0 Unported License along with this +% document. If not, see <http://creativecommons.org/licenses/>. + +% README: Fakultät, Lauflicht, Länge von Strings (Neuauflage) + +\documentclass[a4paper]{article} + +\usepackage{pgscript} +\usepackage{sfmath} + +\begin{document} + + \section*{Hardwarenahe Programmierung\\ + Musterlösung zu den Übungsaufgaben -- 17.\ Dezember 2018} + + \exercise{Fakultät} + + Die Fakultät $n!$ einer ganzen Zahl $n \ge 0$ ist definiert als: + \begin{eqnarray*} + 1 & \mbox{für} & n = 0, \\ + n \cdot (n-1)! & \mbox{für} & n > 0. + \end{eqnarray*} + + Mit anderen Worten: $n! = 1\cdot2\cdot3\cdot\dots\cdot n$. + + Die folgende Funktion \lstinline{fak()} berechnet die Fakultät \emph{rekursiv} + (Datei: \gitfile{hp}{20181217}{aufgabe-1.c}): + + \begin{lstlisting} + int fak (int n) + { + if (n <= 0) + return 1; + else + return n * fak (n - 1); + } + \end{lstlisting} + + \begin{enumerate}[\quad(a)] + \item + Schreiben Sie eine Funktion, die die Fakultät \emph{iterativ} berechnet,\\ + d.\,h.\ mit Hilfe einer Schleife anstelle von Rekursion. + \points{3} + \item + Wie viele Multiplikationen (Landau-Symbol) + erfordern beide Versionen der Fakultätsfunktion\\ + in Abhängigkeit von \lstinline$n$? + Begründen Sie Ihre Antwort. + \points{2} + \item + Wieviel Speicherplatz (Landau-Symbol) + erfordern beide Versionen der Fakultätsfunktion\\ + in Abhängigkeit von \lstinline$n$? + Begründen Sie Ihre Antwort. + \points{3} + \end{enumerate} + + \solution + + \begin{itemize} + \item[(a)] + \textbf{Schreiben Sie eine Funktion, die die Fakultät \emph{iterativ} berechnet,\\ + d.\,h.\ mit Hilfe einer Schleife anstelle von Rekursion.} + + Datei: \gitfile{hp}{20181217}{loesung-1.c} + \begin{lstlisting}[gobble=8] + int fak (int n) + { + int f = 1; + for (int i = 2; i <= n; i++) + f *= i; + return f; + } + \end{lstlisting} + + \item[(b)] + \textbf{Wie viele Multiplikationen (Landau-Symbol) + erfordern beide Versionen der Fakultätsfunktion?} + + In beiden Fällen werden $n$ Zahlen miteinander multipliziert -- + oder $n - 1$, wenn man Multiplikationen mit 1 ausspart. + In jedem Fall hängt die Anzahl der Multiplikationen + linear von $n$ ab; es sind $\mathcal{O}(n)$ Multiplikationen. + Insbesondere arbeiten also beide Versionen gleich schnell. + + \item[(c)] + \textbf{Wieviel Speicherplatz (Landau-Symbol) + erfordern beide Versionen der Fakultätsfunktion?} + + Die iterative Version der Funktion benötigt 2 Variable vom Typ \lstinline{int}, + nämlich \lstinline{n} und \lstinline{f}. + Dies ist eine konstante Zahl; + der Speicherplatzverbrauch ist daher $\mathcal{O}(1)$. + + Die rekursive Version der Funktion erzeugt + jedesmal, wenn sie sich selbst aufruft, + eine zusätzliche Variable \lstinline{n}. + Es sind $n + 1$ Aufrufe; die Anzahl der Variablen \lstinline{n} + hängt linear von $n$ ab; der Speicherplatzverbrauch ist also $\mathcal{O}(n)$. + \end{itemize} + + \exercise{Lauflicht} + + \begin{minipage}[t]{8cm} + An die vier Ports eines ATmega16-Mikrocontrollers sind Leuchtdioden angeschlossen: + \begin{itemize} + \item + von links nach rechts\\ + an die Ports A, B, C und D, + \item + von oben nach unten\\ + an die Bits Nr.\ 0 bis 7. + + \bigskip + + \includegraphics[width=3cm]{leds.jpg} + \end{itemize} + \end{minipage}\hfill + \begin{minipage}[t]{7cm} + Wir betrachten das folgende C-Programm (Datei: \gitfile{hp}{20181217}{aufgabe-2.c}) + für diesen Mikrocontroller: + + \begin{lstlisting}[gobble=6] + #include <avr/io.h> + #include <avr/interrupt.h> + + int counter = 0; + + ISR (TIMER0_COMP_vect) + { + PORTA = 1 << ((counter++ >> 6) & 7); + } + + int main (void) + { + cli (); + TCCR0 = (1 << CS01) | (1 << CS00); + TIMSK = 1 << OCIE0; + sei (); + DDRA = 0xff; + while (1); + return 0; + } + \end{lstlisting} + \end{minipage} + + \medskip + + Das Programm bewirkt ein periodisches Lauflicht in der linken Spalte von oben nach unten. + Eine Animation davon finden Sie in der Datei \gitfile{hp}{20181217}{aufgabe-2.gif}. + + \begin{itemize} + \item[(a)] + Wieso bewirkt das Programm überhaupt etwas, wenn doch das Hauptprogramm + nach dem Initialisieren lediglich eine Endlosschleife ausführt, + in der \emph{nichts\/} passiert? \points 3 + \item[(b)] + Erklären Sie, wie die Anweisung + \begin{lstlisting}[gobble=8] + PORTA = 1 << ((counter++ >> 6) & 7); + \end{lstlisting} + \vspace{-\medskipamount} + das LED-Blinkmuster hervorruft. \points 6 + + Hinweis: Zerlegen Sie die eine lange Anweisung in mehrere kürzere.\\ + Wenn nötig, verwenden Sie zusätzliche Variable für Zwischenergebnisse. + \item[(c)] + Was bedeutet "`\lstinline{ISR (TIMER0_COMP_vect)}"'? \points 1 + \item[(d)] + Wieso leuchten die Leuchtdioden PB2 und PD1? \points 2 + \end{itemize} + + \solution + + \begin{itemize} + \item[(a)] + \textbf{Wieso bewirkt das Programm überhaupt etwas, wenn doch das Hauptprogramm + nach dem Initialisieren lediglich eine Endlosschleife ausführt, + in der \emph{nichts\/} passiert?} + + Die Funktion \lstinline{ISR (TIMER0_COMP_vect)} + ist ein \emph{Interrupt-Handler\/} + (oder \emph{Interrupt Service Routine -- ISR\/}) + und wird nicht durch das Hauptprogramm oder andere Funktionen aufgerufen, + sondern durch ein Hardware-Ereignis. + + In diesem Fall sorgt die Initialisierung dafür, + daß die Funktion regelmäßig durch eine Uhr (\emph{Timer\/}) aufgerufen wird. + + \bigskip + \goodbreak + + \item[(b)] + \textbf{Erklären Sie, wie die Anweisung} + \begin{lstlisting}[gobble=8] + PORTA = 1 << ((counter++ >> 6) & 7); + \end{lstlisting} + \vspace{-\medskipamount} + \textbf{das LED-Blinkmuster hervorruft.} + + Um die Anweisung zu verstehen, zerlegen wir sie in mehrere kürzere. + Dabei ist es wichtig, die Reihenfolge zu erkennen, + in der die einzelnen Operationen ausgeführt werden. + + Zunächst stellen wir fest, daß der Post-Inkrement-Operator \lstinline{++} + erst nach der Anweisung -- also als letztes -- ausgeführt wird. + Die Anweisung ist somit äquivalent zu den folgenden zwei Anweisungen: + + \begin{lstlisting}[gobble=8] + PORTA = 1 << ((counter >> 6) & 7); + counter++; + \end{lstlisting} + + Von der verbleibenden langen Anweisung wird als erstes + die innerste Klammer ausgeführt: + + \begin{lstlisting}[gobble=8] + int temp1 = counter >> 6; + PORTA = 1 << (temp1 & 7); + counter++; + \end{lstlisting} + + Das Verschieben um 6 Binärstellen nach rechts + entspricht einer Division durch $2^6 = 64$. + Die Bedeutung der neu eingeführten Variablen ist somit ein Zähler, + der 64mal langsamer zählt als der ursprüngliche: + + \begin{lstlisting}[gobble=8] + int slow_counter = counter >> 6; + PORTA = 1 << (slow_counter & 7); + counter++; + \end{lstlisting} + + (Ohne diese Verlangsamung wäre das Lauflicht zu schnell, + um es es mit bloßem Auge wahrnehmen zu können.) + + Als nächste Operation wird die bitweise Und-Verknüpfung ausgeführt: + + \begin{lstlisting}[gobble=8] + int slow_counter = counter >> 6; + int temp2 = slow_counter & 7; + PORTA = 1 << temp2; + counter++; + \end{lstlisting} + + Die Binärdarstellung von 7 sind drei Einsen: $7_{10} = 111_2$. + Eine Und-Verknüpfung mit 7 isoliert also die untersten drei Bits + von \lstinline{slow_counter}. + + Mit drei Bits lassen sich Zahlen von 0 bis 7 darstellen. + Wenn also \lstinline{slow_counter} immer größer wird, + läuft \lstinline{slow_counter & 7} immer wieder von 0 bis 7: + + \begin{lstlisting}[gobble=8] + int slow_counter = counter >> 6; + int slow_counter_0_to_7 = slow_counter & 7; + PORTA = 1 << slow_counter_0_to_7; + counter++; + \end{lstlisting} + + (Bemerkung: Eine bitweise Und-Verknüpfung mit 7 ist gleichbedeutend + zur Berechnung des Rests bei Division durch 8: + \lstinline{slow_counter_0_to_7 = slow_counter % 8}. + Auch dadurch wird klar, daß das Ergebnis der Operation + immer wieder die Zahlen von 0 bis 7 durchläuft, + wenn \lstinline{slow_counter} immer größer wird.) + + Die letzte Operation \lstinline{1 << slow_counter_0_to_7} + erzeugt eine Bitmaske, in der ein Bit von Position 0 bis Position 7, + also von rechts nach links wandert: + + \begin{lstlisting}[style=terminal,gobble=8] + 00000001 + 00000010 + 00000100 + 00001000 + 00010000 + 00100000 + 01000000 + 10000000 + \end{lstlisting} + + Die zyklische Zuweisung dieser Bitmasken an \lstinline{PORTA} + erzeugt das Lauflicht. + + \bigskip + + \textbf{Zusammenfassung:} + \begin{itemize} + \item + Das jeweils zum Schluß ausgeführte \lstinline{++}\\ + läßt die Variable \lstinline{counter} bei jedem Aufruf um 1 hochzählen. + \item + Durch die Bit-Verschiebung um 6 nach rechts\\ + erzeugen wir einen um den Faktor 64 langsameren Zähler. + \item + Die bitweise Und-Verknüpfung mit 7 + isoliert die untersten 3 Bit des langsameren Zählers\\ + und erzeugt so einen neuen Zähler, + der immer wieder von 0 bis 7 zählt. + \item + Die Linksverschiebung einer 1 um diesen neuen Zähler + erzeugt Bit-Masken mit jeweils einem Bit, + das von rechts nach links läuft. + \item + Die zyklische Zuweisung dieser Bitmasken an \lstinline{PORTA} + erzeugt das Lauflicht. + \end{itemize} + + \bigskip + + \item[(c)] + \textbf{Was bedeutet "`\lstinline{ISR (TIMER0_COMP_vect)}"'?} + + Es bezeichnet einen \emph{Interrupt-Handler\/} + (\emph{Interrupt Service Routine -- ISR\/}) für einen \emph{Timer-Interrupt}, + also eine Funktion, + die durch ein von einer Uhr periodisch ausgelöstes Hardware-Ereignis + aufgerufen wird. + + \bigskip + + \item[(d)] + \textbf{Wieso leuchten die Leuchtdioden PB2 und PD1?} + + Der Mikro-Controller enthält kein Betriebssystem. + Auf ihm läuft kein Programm außer dem, das wir auf ihn herunterladen. + + Beim Start enthalten alle Ports \textbf{zufällige Werte}. + Wenn wir wünschen, daß eine LED aus ist, + muß unser Programm sie explizit ausschalten. + + In diesem Fall ließe sich dies durch die Zeilen + \begin{lstlisting}[gobble=8] + DDRB = 0xff; + DDRC = 0xff; + DDRD = 0xff; + PORTB = 0; + PORTC = 0; + PORTD = 0; + \end{lstlisting} + im Hauptprogramm erreichen. + + (Wegen der \lstinline{volatile}-Eigenschaft + der \lstinline{DDR}- und \lstinline{PORT}-Variablen + ist dies übrigens \emph{nicht\/} äquivalent zu den folgenden Zeilen: + \begin{lstlisting}[gobble=8] + DDRB = DDRC = DDRD = 0xff; + PORTB = PORTC = PORTD = 0; + \end{lstlisting} + Für Details siehe: + \url{http://www.nongnu.org/avr-libc/user-manual/FAQ.html#faq_assign_chain}) + + \end{itemize} + + \exercise{Länge von Strings} + + Diese Aufgabe ist eine Neuauflage von Aufgabe 3 der + Übung vom 5.\ November 2017,\\ + ergänzt um die Teilaufgaben (f) und (g). + + \medskip + + Strings werden in der Programmiersprache C durch Zeiger auf \lstinline{char}-Variable realisiert. + + Beispiel: \lstinline{char *hello_world = "Hello, world!\n"} + + Die Systembibliothek stellt eine Funktion \lstinline{strlen()} zur Ermittlung der Länge von Strings\\ + zur Verfügung (\lstinline{#include <string.h>}). + + \begin{enumerate}[\quad(a)] + \item + Auf welche Weise ist die Länge eines Strings gekennzeichnet? + \points 1 + \item + Wie lang ist die Beispiel-String-Konstante \lstinline{"Hello, world!\n"}, + und wieviel Speicherplatz belegt sie?\\ + \points 2 + \item + Schreiben Sie eine eigene Funktion \lstinline{int strlen (char *s)}, + die die Länge eines Strings zurückgibt.\\ + \points 3 + \end{enumerate} + + Wir betrachten nun die folgenden Funktionen (Datei: \gitfile{hp}{20181217}{aufgabe-3.c}): + \begin{center} + \begin{minipage}{8cm} + \begin{lstlisting}[gobble=8] + int fun_1 (char *s) + { + int x = 0; + for (int i = 0; i < strlen (s); i++) + x += s[i]; + return x; + } + \end{lstlisting} + \end{minipage}% + \begin{minipage}{6cm} + \vspace*{-1cm} + \begin{lstlisting}[gobble=8] + int fun_2 (char *s) + { + int i = 0, x = 0; + int len = strlen (s); + while (i < len) + x += s[i++]; + return x; + } + \end{lstlisting} + \vspace*{-1cm} + \end{minipage} + \end{center} + \begin{enumerate}[\quad(a)]\setcounter{enumi}{3} + \item + Was bewirken die beiden Funktionen? + \points 2 + \item + Schreiben Sie eine eigene Funktion, + die dieselbe Aufgabe erledigt wie \lstinline{fun_2()},\\ + nur effizienter. + \points 4 + \item + Von welcher Ordnung (Landau-Symbol) sind die beiden Funktionen + hinsichtlich der Anzahl ihrer Zugriffe auf die Zeichen im String? + Begründen Sie Ihre Antwort. + Sie dürfen für \lstinline{strlen()} Ihre eigene Version der Funktion voraussetzen. + \points 3 + \item + Von welcher Ordnung (Landau-Symbol) ist Ihre effizientere Funktion?\\ + Begründen Sie Ihre Antwort. + \points 1 + \end{enumerate} + + \solution + + \begin{itemize} + \item[(a)] + \textbf{Auf welche Weise ist die Länge eines Strings gekennzeichnet?} + + Ein String ist ein Array von \lstinline{char}s. + Nach den eigentlichen Zeichen des Strings enthält das Array + \textbf{ein Null-Symbol} (Zeichen mit Zahlenwert 0, + nicht zu verwechseln mit der Ziffer \lstinline{'0'}) als Ende-Markierung. + Die Länge eines Strings ist die Anzahl der Zeichen + \emph{vor\/} diesem Symbol. + + \item[(b)] + {\bf Wie lang ist die Beispiel-String-Konstante \lstinline{"Hello, world!\n"}, + und wieviel Speicherplatz belegt sie?} + + Sie ist 14 Zeichen lang (\lstinline{'\n'} ist nur 1 Zeichen; + das Null-Symbol, das das Ende markiert, zählt hier nicht mit) + und belegt Speicherplatz für 15 Zeichen + (15 Bytes -- einschließlich Null-Symbol / Ende-Markierung). + + \item[(c)] + \textbf{Schreiben Sie eine eigene Funktion \lstinline{int strlen (char *s)}, + die die Länge eines Strings zurückgibt.} + + Siehe die Dateien \gitfile{hp}{20181105}{loesung-3c-1.c} (mit Array-Index) + und \gitfile{hp}{20181105}{loesung-3c-2.c} (mit Zeiger-Arithmetik). + Beide Lösungen sind korrekt und arbeiten gleich schnell. + + Die Warnung \lstinline[style=terminal]{conflicting types for built-in function "strlen"} + kann normalerweise ignoriert werden; + auf manchen Systemen (z.\,B.\ MinGW) hat jedoch die eingebaute Funktion \lstinline{strlen()} + beim Linken Vorrang vor der selbstgeschriebenen, + so daß die selbstgeschriebene Funktion nie aufgerufen wird. + In solchen Fällen ist es zulässig, die selbstgeschriebene Funktion + anders zu nennen (z.\,B.\ \lstinline{my_strlen()}). + + \item[(d)] + \textbf{Was bewirken die beiden Funktionen?} + + Beide addieren die Zahlenwerte der im String enthaltenen Zeichen + und geben die Summe als Funktionsergebnis zurück. + + Im Falle des Test-Strings \lstinline{"Hello, world!\n"} + lautet der Rückgabewert 1171 (siehe \gitfile{hp}{20181105}{loesung-3d-1.c} und \gitfile{hp}{20181105}{loesung-3d-2.c}). + + \item[(e)] + \textbf{Schreiben Sie eine eigene Funktion, + die dieselbe Aufgabe erledigt wie \lstinline{fun_2()}, + nur effizienter.} + + Die Funktion wird effizienter, + wenn man auf den Aufruf von \lstinline{strlen()} verzichtet + und stattdessen die Ende-Prüfung in derselben Schleife vornimmt, + in der man auch die Zahlenwerte der Zeichen des Strings aufsummiert. + + Die Funktion \lstinline{fun_3()} in der Datei \gitfile{hp}{20181105}{loesung-3e-1.c} + realisiert dies mit einem Array-Index, + Die Funktion \lstinline{fun_4()} in der Datei \gitfile{hp}{20181105}{loesung-3e-2.c} + mit Zeiger-Arithmetik. + Beide Lösungen sind korrekt und arbeiten gleich schnell. + + \textbf{Bemerkung:} Die effizientere Version der Funktion + arbeitet doppelt so schnell wie die ursprüngliche, + hat aber ebenfalls die Ordnung $\mathcal{O}(n)$ -- siehe unten. + + \item[(f)] + \textbf{Von welcher Ordnung (Landau-Symbol) sind die beiden Funktionen + hinsichtlich der Anzahl ihrer Zugriffe auf die Zeichen im String? + Begründen Sie Ihre Antwort. + Sie dürfen für \lstinline{strlen()} Ihre eigene Version der Funktion voraussetzen.} + + Vorüberlegung: \lstinline{strlen()} greift in einer Schleife + auf alle Zeichen des Strings der Länge $n$ zu, + hat also $\mathcal{O}(n)$. + + \lstinline{fun_1()} ruft in jedem Schleifendurchlauf + (zum Prüfen der \lstinline{while}-Bedingung) einmal \lstinline{strlen()} auf + und greift anschließend auf ein Zeichen des Strings zu, + hat also $\mathcal{O}\bigl(n\cdot(n+1)\bigr) = \mathcal{O}(n^2)$. + + \lstinline{fun_2()} ruft einmalig \lstinline{strlen()} auf + und greift anschließend in einer Schleife auf alle Zeichen des Strings zu, + hat also $\mathcal{O}(n+n) = \mathcal{O}(n)$. + + \item[(g)] + \textbf{Von welcher Ordnung (Landau-Symbol) ist Ihre effizientere Funktion?\\ + Begründen Sie Ihre Antwort.} + + In beiden o.\,a.\ Lösungsvarianten + -- \gitfile{hp}{20181105}{loesung-3e-1.c} + und \gitfile{hp}{20181105}{loesung-3e-2.c} -- + arbeitet die Funktion mit einer einzigen Schleife, + die gleichzeitig die Zahlenwerte addiert und das Ende des Strings sucht. + + Mit jeweils einer einzigen Schleife + haben beide Funktionen die Ordnung $\mathcal{O}(n)$. + + \end{itemize} + +\end{document} diff --git a/20181217/loesung-1.c b/20181217/loesung-1.c new file mode 100644 index 0000000000000000000000000000000000000000..c2d6f6003924627ae97831407c191eaac42a09c1 --- /dev/null +++ b/20181217/loesung-1.c @@ -0,0 +1,16 @@ +#include <stdio.h> + +int fak (int n) +{ + int f = 1; + for (int i = 2; i <= n; i++) + f *= i; + return f; +} + +int main (void) +{ + for (int n = 0; n <= 5; n++) + printf ("%d\n", fak (n)); + return 0; +} diff --git a/README.md b/README.md index cb26cc04fed53a98caa64953e55a8033a68f072a..0eba719ef3be6a360e568137241ffd1512b997d0 100644 --- a/README.md +++ b/README.md @@ -60,6 +60,9 @@ Musterlösungen: * [12.11.2018: Text-Grafik-Bibliothek, Datum-Bibliothek, Kondensator](https://gitlab.cvh-server.de/pgerwinski/hp/raw/master/20181112/hp-musterloesung-20181112.pdf) * [19.11.2018: Arrays mit Zahlen, hüpfender Ball](https://gitlab.cvh-server.de/pgerwinski/hp/raw/master/20181119/hp-musterloesung-20181119.pdf) * [26.11.2018: Zahlensysteme, Mikrocontroller](https://gitlab.cvh-server.de/pgerwinski/hp/raw/master/20181126/hp-musterloesung-20181126.pdf) + * [03.12.2018: XBM-Grafik, LED-Blinkmuster](https://gitlab.cvh-server.de/pgerwinski/hp/raw/master/20181203/hp-musterloesung-20181203.pdf) + * [10.12.2018: Trickprogrammierung, Thermometer-Baustein an I²C-Bus](https://gitlab.cvh-server.de/pgerwinski/hp/raw/master/20181210/hp-musterloesung-20181203.pdf) + * [17.12.2018: Fakultät, Lauflicht, Länge von Strings (Neuauflage)](https://gitlab.cvh-server.de/pgerwinski/hp/raw/master/20181217/hp-musterloesung-20181217.pdf) Tafelbilder: ------------ diff --git a/hp-slides-2018ws.pdf b/hp-slides-2018ws.pdf index c22b6bfd1d123bd1b79eb0cf05c629df624905d1..b4f541b3dc39f9f86438dd39f51262aa1a490099 100644 Binary files a/hp-slides-2018ws.pdf and b/hp-slides-2018ws.pdf differ