Übungen zu Computergrundlagen WS 2019/2020
Übungsblatt 12: C++
24. Januar 2019
Allgemeine Hinweise
• Abgabetermin für die Lösungen ist Freitag, 31.01.2020, 11:00 Uhr
• Schickt die Lösungen bitte per Email an Euren Tutor:
– Montag 14:00–15:30: Moritz Schumacher (mschumacher@icp.uni-stuttgart.de) – Dienstag 9:45–11:15: Samuel Tovey (stovey@icp.uni-stuttgart.de)
– Dienstag 15:45–17:15: Philipp Stärk (pstaerk@icp.uni-stuttgart.de) – Mittwoch 15:45–17:15: Marco Brückner (mbrueckner@icp.uni-stuttgart.de) – Donnerstag 9:45–11:15: Ingo Tischler (itischler@icp.uni-stuttgart.de)
• Die Übungen sollen von Gruppen von jeweils zwei (nur in Ausnahmefällen drei) Leuten be- arbeitet werden. Bitte gebt nur eine Lösung pro Gruppe ab und nennt in eurer Abgabe alle Mitglieder eurer Gruppe!
• Als Lösung der Aufgabe soll ein einziges Python-Skript erstellt werden, welche ihr dann per E-Mail an euren Tutor schickt.
Hinweise:
• Wenn der Compiler lange Fehlermeldungen ausgibt, ist es meist hilfreich, die Zeile zu suchen, in derError:steht. Wenn dort auf ein Header-File (z.B.vector) verwiesen wird, kann man so lange nach unten suchen, bis man die Stelle findet, die in der eigenen .cpp-Datei die entsprechende Funktion aus dem Header aufruft.
• Verwendet einen Texteditor, der Syntaxhervorhebung für C++ bietet. Beispielsweise: nano, vim, gedit, emacs, ... unter Linux; TextMate, BBEdit, ... unter macOS; Notepad++, Visual Studio Code, ... unter Windows.
• Kompiliert euren Code mit c++ -std=c++17 -Wall -o programm programm.cppund führt in aus mit./programm.
• Ein laufendes Programm kann jederzeit mit der Tastenkombination Strg-C abgebrochen wer- den. Dies ist nützlich, wenn man beim Programmieren z.B. versehentlich eine Schleife geschrie- ben hat, die nie abbricht.
Aufgabe 12.1: Datentypen (1 Punkt)
Sagt vorher, welches Ergebnis (Wert und Datentyp, oder einen Compilerfehler) folgende Ausdrücke produzieren. Gebt jeweils den Grund dafür an. Nehmt an, dass alle nötigen Header-Files (z.B.
<string>,<cmath>) eingebunden wurden. (1 Punkt)
• 3 + 5
• 3 + 5.0
• "3"+ "5"
• std::string("3") + "5"
• 3 / 2
• 3.0 / 2
• int(2.71828)
• std::round(2.71828)
Aufgabe 12.2: std::vector (2 Punkte)
Schreibt eine Funktion, die alle geraden Zahlen unterhalb einer vorgegebenen Grenze alsstd::vector zurückgibt. Verwendet dafür das Codegerüst unten und testet sie damit. (2 Punkte)
# i n c l u d e < cassert >
# i n c l u d e < vector >
... g e r a d e _ z a h l e n ( . . . ) {
std :: vector <u n s i g n e d int> v ...
for ( . . . ) { ...
}
r e t u r n v ; }
v o i d m a i n () {
a s s e r t ( g e r a d e _ z a h l e n (5) == std :: vector <u n s i g n e d int> ( { 2 , 4 } ) ) ; a s s e r t ( g e r a d e _ z a h l e n (6) == std :: vector <u n s i g n e d int> ( { 2 , 4 , 6 } ) ) ; }
Aufgabe 12.3: Templates (1 Punkt)
Schreibt eine Funktion quadriere(x), die Zahlen eines beliebigen Datentyps quadriert und als eine Zahl desselben Datentyps zurückgibt. Verwendet dafür das Codegerüst unten. (1 Punkt)
# i n c l u d e < cassert >
t e m p l a t e <... >
... q u a d r i e r e ( . . . x ) { ...
}
v o i d m a i n () {
a u t o a = q u a d r i e r e ( 2 ) ; a s s e r t ( a == 4);
a s s e r t (t y p e i d(int) == t y p e i d( a ));
a u t o b = q u a d r i e r e ( 2 . 0 ) ; a s s e r t ( b == 4);
a s s e r t (t y p e i d(d o u b l e) == t y p e i d( b ));
a u t o c = q u a d r i e r e ( 2 . 0 f );
a s s e r t ( c == 4);
a s s e r t (t y p e i d(f l o a t) == t y p e i d( c ));
}
Aufgabe 12.4: Iteratoren (3 Punkte)
Schreibt eine Funktion, die einen beliebigen Container (z.B. std::list, std::vector) mit Zahlen bekommt und die Standardabweichung von diesen berechnet. Verwendet dafür ein Template und testet sie mit Hilfe des Codegerüstes unten. (3 Punkte)
# i n c l u d e < list >
# i n c l u d e < vector >
t e m p l a t e <t y p e n a m e T >
t y p e n a m e T :: v a l u e _ t y p e s t a n d a r d a b w e i c h u n g (c o n s t T & d a t e n ) { t y p e n a m e T :: v a l u e _ t y p e m i t t e l w e r t = 0 , v a r i a n z = 0;
for ( . . . ) { ...
} ...
. . . ...
...
r e t u r n std :: s q r t ( v a r i a n z );
}
v o i d m a i n () {
std :: vector <double> d a t e n 1 = { 525.8 , 605.7 , 843.3 , 1195.5 , 1945.6 , 2135.6 , 2308.7 , 2 9 5 0 . 0 } ; std :: list <float> d a t e n 2 = { 727.7 , 1086.5 , 1091.0 , 1361.3 ,
1490.6 , 1 9 5 6 . 1 } ; a u t o s1 = s t a n d a r d a b w e i c h u n g ( d a t e n 1 );
a s s e r t ( std :: abs ( s1 - 8 9 4 . 3 7 3 ) < 1 e - 3 ) ; a u t o s2 = s t a n d a r d a b w e i c h u n g ( d a t e n 2 );
a s s e r t ( std :: abs ( s2 - 4 2 0 . 9 7 2 ) < 1 e - 3 ) ; }
Aufgabe 12.5: <iostream> (1 Punkt)
Der Code unten, der die Funktion von Aufgabe12.4benutzt, gibt immer mehrere Dezimalstellen auf dem Bildschirm aus. Wir wollen aber nur eine Dezimalstellen sehen. Schlagt in der Dokumentation nach, was ihr hinzufügen musst, um die Genauigkeit für die Ausgabe in eineniostreameinzustellen.
(1 Punkt)
# i n c l u d e < i o s t r e a m >
v o i d m a i n () {
std :: list <float> d a t e n 2 = { 727.7 , 1086.5 , 1091.0 , 1361.3 , 1490.6 , 1 9 5 6 . 1 } ;
a u t o s2 = s t a n d a r d a b w e i c h u n g ( d a t e n 2 );
std :: c o u t < < s2 < < std :: e n d l ; }
Aufgabe 12.6: Ausführungsgeschwindigkeit (2 Punkte)
In der Vorlesung habt ihr gelernt, dass C++ viel schneller sei als Python. Diese Behauptung gilt es, zu überprüfen.
12.6.1 Generiert mit numpy.random.random ein Array mit Zufallszahlen. Benutzt anschließend das Python-Modul timeit, um zu testen, wie lange die folgenden beiden Python-Funktionen pro Daten- punkt brauchen. (1 Punkt)
i m p o r t n u m p y i m p o r t t i m e i t N = 1 0 0 0 0 0 0 0
def s t a n d a r d a b w e i c h u n g _ n u m p y ( d a t e n ):
r e t u r n n u m p y . std ( daten , d d o f =1) def s t a n d a r d a b w e i c h u n g ( d a t e n ):
m i t t e l w e r t = sum( d a t e n )/len( d a t e n )
v a r i a n z = sum([( x - m i t t e l w e r t ) ** 2 for x in d a t e n ]) / (len( d a t e n ) -1) r e t u r n v a r i a n z * * 0 . 5 ;
d a t e n = n u m p y . r a n d o m . r a n d o m ( . . . )
t1 = t i m e i t . t i m e i t ( . . . s t a n d a r d a b w e i c h u n g ( d a t e n ) . . . ) p r i n t( . . . )
t2 = t i m e i t . t i m e i t ( . . . s t a n d a r d a b w e i c h u n g _ n u m p y ( d a t e n ) . . . ) p r i n t( . . . )
12.6.2 Verwendet die C++-Bibliothek std::chrono, um mit folgendem Code zu messen, wie lange eure Funktion von Aufgabe 12.4 braucht. Fügt anschließend -O3 zu eurem Compiler-Aufruf hinzu und messt nochmal.
# i n c l u d e < chrono >
# i n c l u d e < a l g o r i t h m >
# i n c l u d e < vector >
v o i d m a i n () {
u n s i g n e d int N = 1 0 0 0 0 0 0 0 ; std :: vector <double> d a t e n ( N );
r e t u r n std :: r a n d ();
});
a u t o s t a r t = std :: c h r o n o :: h i g h _ r e s o l u t i o n _ c l o c k :: now ();
a u t o s = s t a n d a r d a b w e i c h u n g ( d a t e n );
a u t o end = std :: c h r o n o :: h i g h _ r e s o l u t i o n _ c l o c k :: now ();
a u t o s e k u n d e n = std :: c h r o n o :: d u r a t i o n _ c a s t <
std :: c h r o n o :: n a n o s e c o n d s >( end - s t a r t ). c o u n t ();
std :: c o u t < < " B e r e c h n u n g von " < < s < < " d a u e r t e " < < ( s e k u n d e n / N )
< < " N a n o s e k u n d e n pro D a t e n p u n k t " < < std :: e n d l ; }
Warum ist C++ mit-O3 schneller als ohne, warum ist Python langsamer als C++ und Python mit Numpy schneller als ohne? (1 Punkt)
Hinweis:Erhöht die Anzahl der Datenpunkte so lange, bis die Zeit pro Datenpunkt konstant wird.