So, hallo und guten Morgen.
Herzlich willkommen zur letzten Übung in der Software Technik 1.
Wir haben auf den Übungsblättern gesehen, das freut schon einige, dass
es jetzt endlich rum ist mit diesem stressigen Übungsbetrieb, dass die
meisten doch hoffentlich auch gut durchgekommen sind, auch mit viel
Arbeit.
Ich hoffe, der ein oder andere hat auch trotz des Stresses ein
bisschen was gelernt.
Auch wenn das vielleicht im ersten Moment nicht so ganz offensichtlich
ist und ab und zu, und das werden wir nachher noch in der E-Wahl
sehen, auch mal die Zusammenhänge zwischen Vorlesung, Übung und wahren
Leben noch nicht so ganz offensichtlich sind.
Ich hoffe, das kommt noch irgendwann.
Wenn nicht, tut es mir leid.
Wie sieht es aus?
Was haben wir?
Erinnern wir uns erstmal daran, was wir gelernt haben über die
Parallelität hoffentlich in der Vorlesung.
Es gibt Wettläufe, Wettläufe auf variablen Werte, wie auch immer.
Und das tritt immer dann auf, wenn ich mehrfählige Programme habe, die
auf die gleiche Speicherstelle zugreifen wollen.
Und das passiert irgendwie mit schreibenden Zugriffen in kritischen
Abschnitten.
Und das klassische Beispiel sind immer so Banküberweisungen.
Hole Kontostand 1, hole Kontostand 2, dann subtrahiere Betrag von
Konto 1, addiere zu Konto 2, speichere Kontostand 1 und Kontostand 2.
Ja, alles wunderbar, solange man das nur alleine ausführt.
Wenn da zwei das machen, kann es gut passieren, dass zwischendrin
geschrieben wird, nachdem der andere gelesen hat.
Dann sind da plötzlich andere Werte, als man eigentlich dachte.
Ja, also sowas hier, wenn wir eine Überweisung machen von Konto 1 an
Konto 2 und gleichzeitig eine Überweisung von Konto 1 an Konto 3, dann
können wir eben genau das Problem haben, dass wir den gleichen
Kontostand bei Konto 1 lesen, dann die Überweisung machen und dann die
Überweisung an Konto 3 machen, aber mit dem höheren Kontostand, den
wir vorher hatten.
Das heißt, auf meinem Konto 1 wird mir nur einmal was abgezogen, aber
ich überweise es zweimal an andere Konten.
Ja, und schon habe ich irgendwie Geld generiert.
Und jetzt ist das ja irgendwie kein neues Problem und jetzt ist das ja
irgendwie hoffentlich gelöst.
Und ja, das ist eigentlich gelöst.
Ja, sowas kann man wunderbar in Transaktionen packen und dann ist das
kein Problem mehr.
Das werden Sie wahrscheinlich auch noch im Laufe Ihres Studiums in
aller Ausführlichkeit lernen, was da zu tun ist und welche
unterschiedlichen Varianten man da bauen kann.
Fakt ist jedenfalls, eigentlich kennt man dieses Problem und zwar
nicht erst seit gestern.
Jetzt sollte man auch der Meinung sein, das hat man im Griff.
Die Wahrheit da draußen sieht leider ein bisschen anders aus.
Viele Leute können mit solchen Situationen nicht umgehen und bauen
dann entweder falsche Transaktionsmechanismen oder bauen sowas wie
Timings oder noch schöner, wenn man das in Web-Sessions macht, dass
man einfach sagt, von der IP aus darf nur einmal ein Cookie angelegt
werden, dann ist ja fertig.
Gut einen zweiten Browser daneben legen, gibt es halt nicht im wahren
Leben, das macht ja kein Mensch.
Und so sieht es dann halt auch aus, wenn man das zum Beispiel bei
einem für Technologie bekannten Unternehmen wie Starbucks hat.
Die haben Gutscheinkarten, also so ähnlich wie Konten, wo es halt,
dass man da einmal Geld aufladen kann und was man machen kann mit
diesen Gutscheinkarten oder konnte bei Starbucks, ich hoffe inzwischen
haben sie es gefixt, man kann da Geld von einer Karte zur anderen
überweisen.
Also genau das Szenario, was wir gerade eben auch hatten.
Und tatsächlich kann man damit ziemlich einfach ein Rezept für
unbegrenzten Kaffee bauen.
Und das Rezept ist nicht mehr so furchtbar kompliziert.
Das heißt nämlich einfach nur, kaufe dir zwei Gutscheinkarten mit je
fünf Euro Aufladung und nimm dir ein bisschen Zeit und probiere ein
bisschen rum.
Verlieren kannst du nichts, weil im schlimmsten Fall hast du genauso
viel Geld wie vorher.
Im besten Fall hast du mehr.
Was man dafür machen muss, ist eine Websession selber nachbauen und da
gibt es im Wesentlichen zwei Befehle.
Das macht es dann ein bisschen schwieriger, weil es nicht diese eine
Transaktion gibt, sondern es wird einmal die Transaktion angelegt hier
oben.
Überweisung anlegen.
Man sieht ziemlich gut auch, was passiert.
So ein Geldbetrag von Karte 1 zu Karte 2.
Das alles legt aber erstmal nur diese Überweisung an und im zweiten
Schritt wird das dann ausgeführt.
Das heißt, die eigentliche Transaktion passiert hier unten und das hat
dann mal jemand ausprobiert, ob das da unten kaputt ist.
Wenn man so ein kleiner Hacker ist, dann macht man ja gerne mal solche
Dinge.
Denkt sich, dieses Ding da, das könnte kaputt sein, dieses Confirm.
Was passiert denn, wenn man das gleichzeitig ausführt?
Und dann baut man sich so einen Pseudocode.
Für den Hacker habe ich den mal mitgebracht.
Was man machen muss, ist tatsächlich nicht so furchtbar kompliziert.
Man braucht einfach nur zwei Sessions, in denen man diese Transaktion
anlegt und dann möglichst gleichzeitig hier unten abschickt, diese
beiden Transaktionen.
Und das macht man dann mal und dann passiert erstmal fünf, sechs mal
nichts, einfach nur das Geld von der einen Karte auf die andere
überwiesen.
Und beim sechsten Mal hat man dann plötzlich diese Situation.
Plötzlich ist da auf der einen Karte null Dollar drauf.
Okay, das war zu erwarten, weil fünf runter von der einen.
Fünf rauf auf die andere, aber auf der anderen irgendwie 15 Dollar.
Und was macht man da?
Weil man natürlich ein guter Mensch ist, sagt man, okay, das war jetzt
irgendwie unfair und das ist ja irgendwie ein Fehler.
Und vielleicht sollten wir das nicht ausnutzen, auch wenn wir es
könnten, sondern wir weisen vielleicht mal dieses sehr sympathische
Großunternehmen darauf hin, dass da irgendwas kaputt ist.
Und außerdem möchte man natürlich ein Proof of Concept haben, dass das
auch tatsächlich funktioniert und dass das nicht irgendwie zum
Beispiel nur ein Fehler in der Darstellung ist.
Also man kann sich auch online anschauen, wie viel Geld auf den Karten
ist und da steht dann halt 15 Dollar bei der einen, aber das könnte ja
auch nur sein, dass das Webfrontend da was Falsches anzeigt.
Vielleicht ist es ja irgendwo richtig gespeichert.
Also was muss man machen?
Starbucks gehen und da tatsächlich was kaufen im Wert von 15 Dollar.
Und das ist gar nicht so schwierig.
Da braucht man irgendwie ein Sandwich und einen Kaffee.
Und das hat derjenige, der das da zusammen gehackt hat, auch gemacht.
Ganz wichtig, das habe ich hier unten jetzt noch, vorher noch den
Dollar aufladen auf die Karte, weil ansonsten ist man wegen Betruges
dran.
Und das ist in Amerika passiert, das heißt, da ist man dann schon mal
lebenslänglich weg, wenn man ein großes Unternehmen wegen 10 Dollar
betrügt.
Dementsprechend lieber das mal vorher noch machen.
Und das Witzige war, er hat da einfach bei Starbucks eingekauft für 13
,70 Dollar und das hat funktioniert.
Also war offensichtlich tatsächlich 15 Dollar auf diesem Konto.
Hat da wirklich 5 Dollar einfach erschaffen aus dem Nichts und wollte
dann mit jemanden sprechen, um zu sagen, naja, hier können wir
vielleicht mal mit der Technikabteilung sprechen.
Ging gar nicht.
Dann hat er irgendwann eine E-Mail-Adresse bekommen, da hat er da
hingeschrieben.
Dann ist erst mal 10 Tage nichts passiert.
Und nach 10 Tagen kam dann so eine Antwort wie, ja, Betrug und wir
werden Sie verklagen und so weiter und so fort.
Aber keiner hat mal Danke gesagt.
Und das ist eben häufig das Problem, wenn man schon auf der guten
Seite steht und eigentlich so ein White Hacker ist, dass man dann auch
noch eigentlich angeklagt wird für das, was man tut, was ein bisschen
schade ist.
Deshalb, wenn einer von Ihnen diese Karriere anstrebt, immer an solche
Dinge denken.
Ja, hier selber absichern, dass man da nicht irgendwie noch des
Betruges bezichtigt werden kann.
Und für alle anderen, die wahrscheinlich eher auf der anderen Seite
landen, nämlich Systeme zu bauen, die hoffentlich sicher sind.
Du meinst gerade die andere Hackers-Seite?
Nee, nee.
Ach, von mir aus auch.
Wir geben Ihnen gerne das Grundzeug mit dafür, ein richtig guter
Hacker zu werden, indem wir Ihnen zeigen, wie man Systeme richtig baut
und Sie wissen, wo sie kaputt sein könnten.
Ach so, ja.
In dem Fall ist es tatsächlich ja gar nicht so schwierig gewesen.
Und der Blogpost, der dazu war, der war auch so ein bisschen, ja,
jetzt, wo keine Reaktion bei Starbucks passiert ist, könnte ich das ja
einfach machen und mal gucken, wie lange es dauert, bis Starbucks sich
doch mal rührt.
Machen Sie es nicht, ja.
Also es ist dann doch gerade als Informatiker auch ganz gut, mit
ehrlicher Arbeit Geld zu verdienen.
Dementsprechend würde ich Ihnen das jetzt nicht unbedingt empfehlen.
Aber wenn Sie mal auf der anderen Seite stehen, also nicht auf der
schwarzen Hacker-Seite, sondern auf der Entwickler-Seite, denken Sie
an sowas, ja.
Denken Sie zurück an die SVT, denken Sie dann später auch zurück an
die Dinge, die Sie sonst noch lernen werden über Transaktionen und
ähnliches.
Vielleicht beschäftigen Sie sich ja auch später mal im Studium noch
mit Sicherheit.
An all das denken bitte, wenn Sie sowas entwickeln, weil von dieser
Sorte Code ist leider auf dieser Welt viel zu viel im Umlauf und das
muss jetzt nicht noch mehr werden.
Gut, das dazu.
Das war Ende des Quatsches heute.
Jetzt machen wir weiter mit der Übung erst mal.
Wir haben auch noch die EWAL-Folien dabei.
Sie haben uns ja freundlichst evaluiert und das werden wir auch noch
besprechen, allerdings etwas später.
Wir haben uns gedacht, wir machen das jetzt so, wir machen die ersten
vier Übungsaufgaben erst mal durch und dann vor der letzten gibt es
noch mal die Evaluation, die ich natürlich jetzt aufgemacht habe, was
natürlich völliger Quatsch ist.
Ich wollte ja die Übung machen.
Das war so ein Teaser.
Das war ein Teaser, ja.
Also ich habe die Folien wirklich, ja.
Also es wird eine EWAL geben, aber jetzt gibt es erst mal Übungen.
Wir haben als erste Aufgabe klassisch und deshalb haben wir gerade
eben auch mit den Data Races angefangen, immer die Parallelisierung.
Seit letztem Jahr ein bisschen anders, als wir es sonst immer hatten.
Früher gab es immer nur den Parallelisierungswettbewerb, also die
Aufgabe 2 vom aktuellen Übungsblatt.
Das hat mir persönlich aber nicht so gut gefallen, weil das 90 Prozent
der Leute nicht gemacht haben, weil der immer nur steht, machen Sie
mal so schnell wie möglich.
Herzlichen Glückwunsch.
Das hat halt viele Leute abgeschreckt, gerade die Leute, die jetzt
vorher noch nicht so viel mit Parallelisierung gemacht haben.
Und dann war es halt häufig so irgendwie 13 Punkte oder 0.
Das fand ich persönlich immer ein bisschen unfair, deshalb haben wir
uns überlegt, das ein bisschen umzubauen, um zu sagen, wir machen eine
vergleichsweise einfache Parallelisierungsaufgabe.
Ich weiß, dass das fordernd ist, im zweiten Semester sich damit zu
beschäftigen, aber zumindest eine Aufgabe, wo wir klar sagen, an
welchen Stellen und wie zu parallelisieren ist.
Und das hat zumindest letztes Jahr ganz gut geklappt.
Dieses Jahr bin ich leider nicht dazu gekommen, zu schauen, wie viele
tatsächlich abgegeben haben, aber ich hoffe, es waren auch dieses Jahr
wieder ein paar mehr, als das sonst nur bei den reinen
Parallelisierungswettbewerbsaufgaben war.
So, was war jetzt bei Aufgabe 1 zu tun?
Oder machen wir es nochmal anders.
Wer hat denn die Aufgabe 1 gemacht von Ihnen?
Wer war denn so mutig?
Na ja, immerhin ein paar.
Gut.
Dann für die paar erkläre ich kurz, was zu tun war.
Wir wollten unseren Algorithmus zur Berechnung der HDR-Bilder
parallelisieren, weil das offensichtlich viel schneller geht.
Parallelisierung ist gerade in der Bildverarbeitung eigentlich so ein
wunderbares Mittel.
Wird gerade da gerne verwendet.
Es bietet sich einfach an.
Es ist auch schön anschaulich, warum das gut funktioniert.
Wir hatten dieses Mal Matrix-Operationen.
Normalerweise haben wir sowas wie, wir zerschneiden das Bild in
Streifen und parallelisieren darüber.
Das sieht man einfach mal ganz gut, was da zu machen ist.
So, was haben wir dieses Mal gemacht?
Wir haben einmal die Berechnung der Farbkanäle parallelisieren lassen
von Ihnen als Bonusaufgabe.
Das ist irgendwie auch offensichtlich drei Farbkanäle, drei Threads.
Die sind absolut unabhängig voneinander.
Das müsste ja irgendwie gehen, dass man das nebenläufig berechnet.
Dann hatten wir die Matrix-Multiplikation, die ja auch in der
Vorlesung vorgestellt wird, der IJK-Algorithmus umzusetzen.
Und zuletzt sollte man es halt noch lauffähig bekommen.
Also eine HD-Rise-Parallel-Variante bauen, die dann im Grunde die
Aufrufe so weiter delegiert, dass man am Ende auch die tatsächlich
parallelen Ausführungen jeweils hat.
So, und jetzt schauen wir uns mal an, wie das genau aussieht.
Wir fangen mal an mit der Kamerakurve.
Das war, wie gesagt, die Bonusaufgabe.
Im Wesentlichen ist da nicht viel zu tun, außer ein Konstruktor
anlegen, der die die Anzahl der Fäden setzt.
Wir haben zwischendrin noch ein bisschen unsere Oberklasse geändert,
sodass man dort zugreifen konnte.
Man konnte aber an der Stelle auch einfach den Altcode kopieren.
Das waren die zwei Varianten.
Wir haben das zwischendrin versucht, zu kommunizieren.
Das Problem war halt an der Stelle, dass wir, weil jetzt wir das
gebaut haben, die ursprüngliche Variante nicht aufgepasst haben, dass
man das ja brauchen könnte in der parallelen Variante später mal.
Oder wir wussten noch gar nicht, was wir parallelisieren wollen.
Also sehen Sie mal wieder ein klassisches Beispiel für aufgepasst,
wenn man Schnittstellen baut.
So, was ist dann zu tun?
Wir berechnen jetzt wieder die einzelnen Farbkanäle.
Das ist alles Altcode, das ist alles unverändert.
Also auch nicht so richtig schön, wenn man das richtig bauen wollte,
würde man wahrscheinlich auch wieder anfangen mit einer Oberklasse und
mit einer Schablonmethode, wenn man das nicht doppelt baut.
So, und das ist jetzt das, was hier eigentlich passiert.
Wir haben hier einmal die Variante, wir haben zu wenig Fäden, das
heißt 1 oder kleiner übergeben.
Dann machen wir einfach die sequenzielle Variante, rufen einfach
Calculate Channel ganz normal auf, berechnen die einzelnen Kanäle
nacheinander.
Das ist die eine Variante.
Variante 2, wir haben zwei Kanäle.
Da haben wir das so gemacht, gesagt, okay, wir haben einen Faden, der
rot und grün berechnet und wir haben einen, der blau berechnet und
fertig.
Das hätte man natürlich auch anders machen können.
Also wie man das macht, ist eigentlich relativ egal.
Man kann das anders kombinieren.
Auf alle Fälle, wir haben das jetzt halt so gemacht.
Das ist nicht ganz optimal, das ist uns auch bewusst, aber so
funktioniert es auf jeden Fall.
Und jetzt die Variante mit den Fäden, größer gleich 3, dann nehmen wir
eben genau drei Fäden, auch wenn wir da irgendwie 5 angeben, die wir
benutzen könnten.
In der Methode benutzen wir immer genau drei und legen halt für jeden
Faden, für jeden Kanal einen Faden an und berechnen dann dort wieder
die Kanäle und fertig.
In der Aufgabenstellung war gesagt, machen Sie das so, dass es
sinnvoll ist und sinnvoll ist offensichtlich drei Kanäle.
Also wenn Sie nur sowas hier gebaut haben, was einfach nur für drei
Fäden funktioniert und sich sichergestellt haben, dass das entweder
mit drei Fäden funktioniert oder sequenziell und diese zwei Faden
-Variante weggelassen haben oder die ein Faden-Variante, völlig in
Ordnung.
Also unsere Lösung ist hier wieder größer, als es sein müsste.
So, am Ende wieder das, was wir damals auch schon gebaut hatten, mit
dem, wenn es nicht funktioniert hat, dann probieren wir es halt noch
mal und standardmäßig sind es bei uns drei Versuche für die Berechnung
der Kanäle.
Gut, wunderbar.
Das war das Ganze zur Bonusaufgabe.
Nicht so furchtbar spannend, deshalb schauen wir doch gleich mal rein,
wie das jetzt mit der Matrix-Berechnung ist.
Es gibt irgendwo drängende Fragen.
Eine.
Da oben ist eine, ja.
Das ist eine sehr gute Frage, die habe ich auch schon gestellt, weil
ich habe es nicht selber implementiert.
Gebe ich zu, wir haben einen Tutor, der uns bei der Implementierung
hilft.
Ich habe auch gesagt, was ist das denn?
Es gibt wohl den Fall, dass die Berechnung nicht funktioniert, weil
ich ungünstige Samples ziehe und ich dann nicht inventierbare Matrizen
bekomme.
Ich glaube, das war das Problem.
Und dann kann ich nicht weiterrechnen und dann muss ich es halt noch
mal probieren.
Der Fall tritt aber sehr selten auf und deshalb ist bei uns die Magic
Number 3 mit dem Hinweis, machen Sie das im wahren Leben bitte nie so.
Ich bin da selber ehrlich gesagt auch nicht so wirklich glücklich
damit, aber hatte auch auf die Schnelle keine bessere Idee.
Man hätte es natürlich auch machen können, bis es funktioniert und
wahrscheinlich wäre da auch nie ein Fehler aufgetreten, aber man weiß
es halt nicht.
Andere Variante wäre gewesen zu sagen, okay, geht jetzt halt nicht.
Bitte starte es neu oder lass es.
Ich habe ehrlich gesagt keine gute Lösung dafür.
Dann, ja bitte noch.
Ja genau, also er kommt in die Tonne und sagt, wenn die Matrix
inventierbar ist und es kaputt geht und es trotzdem nicht
funktioniert, dann muss irgendwas anderes kaputt sein.
Ja klar, aber das ist nicht der Fall, der hier auftritt.
Also es ist tatsächlich nur, wenn die Matrix nicht inventierbar ist.
Das Problem ist, das passiert sehr selten, aber die Stochastik lehrt
uns, es kann trotzdem jedes Mal wieder passieren.
Also theoretisch könnte das, wenn wir sagen, wir machen so lange bis
die Matrix inventierbar ist, könnte das Programm ewig laufen.
Deshalb ist es bei uns halt 3.
Hat sich als empirischer Wert bewährt.
So gut ist die Lösung aber tatsächlich nicht, das gebe ich zu.
Okay, dann schauen wir mal rein in die Berechnung der Matrizen.
Das haben wir gelöst, das stand ja auch als Hinweis dabei, dass man
das machen könnte mit einem Threadpool.
Schauen wir gleich nochmal drauf, wie das funktioniert.
Auch hier wieder, wenn wir zu wenig Fäden haben, dann bauen wir halt
keinen Threadpool, dann wird es später sequenziell ausgerechnet, was
auch immer wir tun wollen.
Und wenn wir genug Fäden haben, dann bauen wir einen Threadpool und
zwar mit einer festen Größe Anzahl der Threads.
So sieht das dann aus schematisch.
Wir haben hier den Threadpool, in dem Fall für acht Fäden gebaut und
man kann dann Aufgaben definieren und in eine Aufgabenschlange
einreihen und dann sagen hier Threadpool go und was dann passiert,
dann werden die Aufgaben nacheinander an freie Fäden übergeben, die
berechnen, geben eine Ausgabe aus und sobald sie wieder frei sind,
können sie wieder eine neue Aufgabe entgegennehmen.
Das ist sehr schön zu programmieren.
Es ist nicht die unbedingt schnellste Variante, um parallel zu
programmieren, aber es funktioniert hier ziemlich handlich und lässt
sich jetzt auch gut zeigen.
Das kann man also auf jeden Fall tun und es gibt auf jeden Fall auch
eine ordentliche Beschleunigung dadurch.
Ist natürlich insbesondere dann hilfreich, wenn man einfach weiß, man
hat eine deutlich größere Anzahl an Aufgaben, als man an Fäden zur
Verfügung hat.
Also besonders dann natürlich, wenn man vorher nicht weiß, wie groß
die Aufgabenzahl wird.
Die Situation hat man ja tatsächlich sehr häufig.
In unserem Fall hätte man das ja sogar gewusst oder hätte man das ja
sogar beeinflussen können.
Wie funktioniert das jetzt?
Hier unten ist eigentlich der spannende Teil.
Nämlich, wir haben gesagt und auch das wieder als Hinweis, war nicht
gefordert.
Parallele Berechnungen nur dann machen, wenn unsere Matrix auch groß
genug ist.
Und das machen wir deshalb, weil sowohl das Anlegen des Threadpools
als auch die Thread-Erzeugung immer einen gewissen Overhead erzeugt in
Java.
Da müssen Sie ja immer daran denken, wenn Sie Parallelisierung
betreiben, machen Sie das nur, wenn die Problemgröße das auch hergibt.
Also es hilft nix, irgendwie 128 Threads anzulegen, um dann eine 1x1
-Matrix zu berechnen, berechnen zu lassen von einem.
Also das ist irgendwie Quatsch.
Da erzeugen Sie nur Laufzeit, die nix tut.
Deshalb haben wir das gemacht.
Wie gesagt, das war nicht gefordert.
Wer sich darüber Gedanken gemacht hat, sehr schön.
Ansonsten sehen Sie es hier als Hinweis, dass man das beachten sollte.
Und dann gibt es hier unten den Aufruf einer privaten Methode, die das
parallele Multiplizieren tut.
Die sehen wir dann gleich auch noch auf der nächsten Folie.
Was haben wir jetzt hier?
Wir haben hier erstmal den Threadpool angelegt.
Ganz oben.
Ne, da ist er.
Ah, das war vorher schon ein Konstruktor.
Schauen wir nochmal zurück.
Hier schon?
Ah ja, du hast recht.
Natürlich, den haben wir schon gemacht.
Genau.
Was wir jetzt machen, wir haben jetzt hier eine Liste von Threads.
Und wir können dann mit diesen Threads jeweils sagen, für die Anzahl
der Threads berechne oder mache diese Berechnung des Multiplies auf
deinem Teil.
Dafür brauchen wir hier im Grunde den Teil der Matrix, der berechnet
werden soll.
Und das ist dann genau das, worüber später parallelisiert wird.
Also beim IJK-Algorithmus wird über die äußerste Schleife, also über
das I parallelisiert.
Das heißt, das ist genau das, was wir hier übergeben.
Und das sehen wir jetzt hier in der privaten Methode.
Jetzt übergeben wir nämlich, das haben wir gerade eben gesehen, dieses
I -Start und I-End, damit wir wissen, diesen Teil der Schleife, des
IJK -Algorithmus, müssen wir ablaufen als einzelner Thread und dort
die Berechnung durchführen.
Ja, also nochmal zurück.
Das sind genau diese hier.
Also wir berechnen uns für den Thread jeweils den Anteil, den er
berechnen soll.
Und dann machen wir einfach ganz normal den IJK-Algorithmus, wie man
ihn in jedem Lehrbuch findet oder auf jeder Internetseite, wenn man
nach IJK googelt.
Genau.
Das, was haben wir noch?
Das ist jetzt schon der nächste Teil.
Wir bleiben mal noch ganz kurz hier stehen.
Gibt es dazu Fragen zum IJK?
Ja.
Genau.
Da müssen Sie halt dafür sorgen, dass Sie, wie das hier passiert bei
unserer Schleife, dass bei der Erzeugung des Threads die richtigen
Variable, die richtigen Argumente übergeben werden.
Die muss man halt an der Stelle tun.
Also Sie können wahrscheinlich nicht einmal fest sagen für alle Fäden,
das ist jetzt Start und das ist Ende, sondern das müssen Sie
offensichtlich berechnen, weil das hängt ja gegebenenfalls von der
Anzahl der Threads ab und von der Problemgröße.
In dem Fall haben wir das natürlich jetzt nicht.
In dem Fall hängt es jetzt nur von der Anzahl der Fäden ab.
Und die stimmt gar nicht.
Wir haben hier immer noch die Rows.
Also es hängt natürlich auch von der Problemgröße ab.
Das Lambda in der Vorschleife, genau, baut das Runnable.
Okay.
Noch mehr dazu?
Da kommt noch eine Frage.
Achso, Sie wollen wissen, ob hier nur aufgerufen wird, aber nicht
gewartet wird, bis alle fertig sind.
Das ist das Schöne, wenn wir so ein Threadpool benutzen, das wird uns
da abgenommen.
Also normalerweise müssten Sie ja starten, enden und joinen wieder.
Das haben wir, glaube ich, auch auf den Folien der Vorlesung.
Wenn Sie den Threadpool benutzen, dann bekommen Sie einfach hinten die
Aufgabenschlange wieder raus.
Ja, der Threadpool lebt so lange, wie Sie ihn nicht beenden, oder?
Der Hauptfaden muss halt weiterlaufen.
Genau, der Hauptfaden läuft halt weiter.
Der Hauptfaden muss weiterlaufen.
Wenn der beendet ist, der Mainfaden, dann sind natürlich alle
Hintergrundfäden vom Threadpool auch beendet.
Das müssen Sie halt sicherstellen.
Aber die Ergebnisse bekommt man halt auch vorher schon, die
Ergebnisschlange.
Okay, so, jetzt müssen wir noch dafür sorgen, dass das Ganze auch
irgendwie funktioniert in unserem Ökosystem.
Bisher haben wir nur die einzelnen Kanäle parallelisiert und die
Matrixmultiplikation.
Und jetzt wollen wir natürlich, dass wir auch unser HDRIs parallel
aufrufen können.
Das ging ja bisher jetzt von außen nicht.
Das war jetzt die Aufgabe D, glaube ich, genau.
Und da muss man jetzt im Grunde einfach nur sehen, dass man an die
richtigen Stellen delegiert und an einer Stelle ein bisschen
aufpassen.
Da wird es dann ein bisschen tricky.
Das sehen wir gleich.
Und zwar gleich hier schon auf der nächsten Folie.
Hier nochmal, das war einfach gefordert.
Wir wollen einen Standardkonstruktor haben, der sagt, nimm so viele
Prozessoren, wie du zur Verfügung hast.
Und da gibt es einfach genau diesen Aufruf, der uns diesen
Systemparameter gibt.
Und netterweise gibt uns dieser Aufruf sogar die virtuellen
Prozessoren mit.
Also wenn Sie irgendwie einen Vierkerner mit Hyper-Threading haben,
dann bekommen Sie an der Stelle eine 8 zurückgeliefert.
Also da ist man einfach schon fertig.
Mehr muss man tatsächlich nicht tun.
Es ist ziemlich komfortabel.
Genau, ansonsten sollte ja noch ein Konstruktor angelegt werden, bei
dem man einfach fest sagen kann, das soll jetzt die Anzahl der Threads
sein.
So, und jetzt kommt der spannende Teil.
Jetzt musste man das Create RGB neu bauen und das sollte im
Wesentlichen so aussehen wie das alte auch.
Nur müssen wir jetzt natürlich sehen, dass wir dieses Create Curve
anders aufrufen und zwar an zwei Stellen.
Wir wollen ja jetzt hier einmal das Parallel machen.
Wo sieht man das eigentlich?
Gar nicht.
Ja, dass das eine parallele Kamerakurve ist.
Also, weshalb ich diese Zeile gehighlighted habe, ist, weil da ein
Problem auftritt, wenn wir das mit unserer Implementierung, so wie wir
das gebaut haben, aufrufen würde.
Und zwar haben wir ja gesagt, wir wollen in der Bonusaufgabe jeden
Kanal einzeln berechnen.
Jetzt ist das Problem, dass in der Kanalberechnung die
Matrixmultiplikation benutzt wird.
Das heißt also, wenn wir das einfach so benutzen, wie wir es gerade
gebaut haben, dann bauen wir hier einen Faden pro zu berechnenden
Kanal und dann jeweils noch mal so viele Fäden, also noch mal zum
Beispiel 8, wenn wir vorher 8 ausgelesen haben, pro
Matrixmultiplikation.
Das heißt, wir haben am Ende irgendwie das in den Griff bekommen.
Es gibt ja unterschiedliche Varianten, das schön zu machen.
Wir haben das in unserem Fall einfach gemacht, indem wir gesagt haben,
wir haben dann durch diese parallele Berechnung der Kamerakurve haben
wir dreimal so viele Fäden, wie wir hätten haben wollen.
Deshalb nehmen wir unsere geforderten Fäden und teilen die durch drei
nach unten, abgeschätzt die Anzahl der Fäden.
Es gibt viele andere schöne Varianten, wie man das machen kann.
Wir haben da auch andere gebaut.
Man kann das auch in der Matrix noch aufräumen, in der
Matrixberechnung noch aufräumen.
Man kann es beim Aufruf des parallelen Berechnung der Farbkanäle kann
man das auch noch aufräumen.
Also es gibt unterschiedliche Varianten.
Das ist jetzt die, die am besten funktioniert, wenn man entweder das
eine gebaut hat oder das andere.
Also das hat am wenigsten Einfluss, wenn man die Bonusaufgabe nicht
gemacht hat.
Deshalb haben wir das so gemacht.
Ein Kommilitone hat einen besseren Vorschlag.
Eine Frage.
Also ihr Kommilitone sagt, er war besonders fleißig und hat das auch
noch vermessen.
Und bei ihm war es am schnellsten, wenn er das nicht gemacht hat,
sondern weil er einfach gesagt hat, zum Beispiel für acht Fäden und
für die drei Kanäle, dann waren es halt 24 Fäden und das war trotzdem
noch schneller, als wenn er das extra so gemacht hat, dass es sich wie
hier runterrechnet.
Müsste man glaube ich im Detail reinschauen, warum das so ist.
Ich kann mir vorstellen, dass es so ist und zwar hauptsächlich
deshalb, weil die Problemgröße ja doch relativ groß war.
Das heißt also, der Overhead durch das Erzeugen des Threadpools ist
wahrscheinlich gar nicht so groß, zumal es ja egal ist, ob wir den
Threadpool anlegen für acht oder für drei Fäden.
Und dann könnte es tatsächlich sein, dass wir schätzen das ja hier
nach unten ab, dass unsere Threadpools für die Berechnung der Matrizen
dadurch zu klein werden, dass wir im Grunde immer einen Teil haben,
der warten muss, weil der Threadpool nach unten abgeschätzt ist und
dann dadurch zu klein ist.
Das könnte sein, dass das der Effekt ist.
Vielleicht funktioniert, wenn man es nach oben abschätzt, besser.
Sie sollten aber wahrscheinlich eh keinen großen Unterschied sehen
zwischen der Ausführung, also vorausgesetzt, Sie haben korrekt
parallelisiert sehen Sie wahrscheinlich eh keinen großen Unterschied
zwischen acht und 24 Fäden, wenn Sie acht echte Fäden haben.
Also so viel Overhead wird dann doch nicht erzeugt.
Und dann denke ich mal, ist der Verschnittfaktor wahrscheinlich das
größere Problem, könnte ich mir vorstellen.
Aber das ist jetzt nur so ein erstes Raten, warum das so ist, müsste
man da noch mal genau reinschauen.
Okay, sonst noch Fragen, Anmerkungen?
Nee, es werden dann drei Threadpools angelegt.
Es wird ja jeder Faden, also jeder legt ja dann wieder selber, also je
nachdem, wie Sie implementiert haben.
Ich kann ja jetzt nicht sagen, wie das bei Ihnen ist.
In unserer Implementierung müsste das so sein, ja.
Insofern, ja, also da werden tatsächlich dann drei Threadpools mit
jeweils acht angelegt, wenn wir es einfach so benutzen, wie wir es
gebaut haben.
Aber auch hier gilt wieder, wenn Sie das übersehen haben und nicht
gemacht haben, ja, völlig egal.
Weil also das ist was, das fällt einem irgendwie so auf, nach drei
Tagen an den Problemen rumschrauben, dass da plötzlich irgendwie mehr
Fäden sind, als man denkt.
Das würden wir jetzt tatsächlich nicht erwarten, dass man das, wenn
man das erste Mal mit Parallelität hantiert, dass man einem das
auffällt.
Nee, also es wird tatsächlich in unserer Implementierung zumindest
jeweils ein Threadpool dann angelegt für die Pro-Kanal.
Okay, gut.
Was müssen wir noch machen?
Ah, hier sieht man es jetzt, genau.
Wir müssen noch diese parallele Kamerakurve haben, genau.
Und an der Stelle wird dann eben unser Matrix-Calculator, den wir
jetzt gerade mit Threadanzahl Drittel gebaut haben, übergeben.
Okay, das ist alles, was man tun musste.
So ein paar delegierende Schritte, damit dann auch das aufgerufen
wird, was man haben will.
Das war schon die ganze Aufgabe.
Wer ist denn der Meinung, dass es hinbekommen hat, die Aufgabe 1?
Der Selbstbewusste, die sich sehr schnell gemeldet haben.
Sehr schön.
Ein paar Zögerliche noch.
Okay, sehr schön.
Ist wie gesagt ein wichtiges Thema und ich weiß, ein bisschen
schwierig im zweiten Semester, aber man wird sich damit beschäftigen
müssen.
In der aktuellen Arbeitswelt ist es doch sehr weit verbreitet, dass
man das auch können muss.
Okay, gut.
Zweite Aufgabe war Parallelisierungswettbewerb.
Das wird unsere Testumgebung sein.
Vielleicht benutzen wir noch einen zweiten Rechner, je nachdem, ob die
Zeit dafür nächste Woche reicht.
Und das ist jetzt auch schon der Hinweis.
Wir können Ihnen das jetzt leider noch nicht liefern, wer da der
Gewinner ist.
Das liegt einfach daran, dass Abgabe am Mittwoch war.
Ja, dann müssen erstmal die Tutoren jeweils herausfinden, wer denn bei
Ihnen der schnellste war, weil wir können nicht alle Abgaben
anschauen.
Das dauert halt einen Moment.
Und wenn wir dann irgendwie so zehn, zwölf Kandidaten haben, dann
schauen wir uns die alle im Detail an.
Und dann gibt es in der letzten Vorlesung die Siegerehrung dazu.
Wer von den hier Anwesenden hat das denn gemacht überhaupt,
Parallelisierungswettbewerb?
Ja, wenn das nur die wären, dann hätten wir auch heute schon die
Ergebnisse.
Ja, aber es sind tatsächlich ein paar mehr.
Also ganz so einfach ist es nicht.
Okay, also tut mir leid, da müssen Sie sich noch kurz gedulden.
Dafür gibt es dann nochmal ein paar hübsche Folien mit, wie schnell
sind denn die unterschiedlichen Leute im Vergleich zueinander und auch
warum ist das denn so schnell.
Sie haben noch eine Frage?
Ist schon bekannt, was man gewinnen kann, fragt ihr Kommilitone.
Ja, ist uns bekannt.
Ja, Informatiker.
Das ist die Antwort, die man dann kriegt.
Nein, also Sie wollen wahrscheinlich gerne wissen, was es zu gewinnen
gibt.
Dann will ich mir nicht weiter auf die Folter spannen.
Es wird einen Amazon-Gutschein geben für den Gewinner.
Ich weiß leider nicht mehr die Höhe.
Das ist tatsächlich mir jetzt gerade nicht bekannt, aber es ist ganz
nett, sage ich mal so, sowas zu bekommen.
Und was es natürlich auch gibt, ist hier die große Auszeichnung vor
allem.
Ja, Händedruck von Professor Tichy.
Nennung des Namens auf YouTube.
Also was will man mehr?
Also ein Traum von einer Preisverleihung.
Okay, nochmal kurz zurück zum Ernst des Lebens und damit zu Martin.
Wir hatten noch drei weitere Aufgaben auf dem Übungsblatt und zwar
zunächst erstmal, was war das eigentlich?
Äquivalenzklassen.
Wunderbar, genau.
Funktionales Testen war die Aufgabe, Aufgabe 3.
Wir hatten Ihnen so eine Schnittstelle gegeben, dieses i-Konto und
hatten Sie dann gebeten, Äquivalenzklassen zu bestimmen und später
auch Grenzwerte für Ihre Äquivalenzklassen zu bestimmen.
Wenn Sie da ein bisschen in den Java-Doc reinschauen, dann fällt Ihnen
vielleicht ein bisschen was auf.
Dieser Betrag, dieser abzuhebende Betrag ist schon mal als größer
gleich 0 definiert.
Ich könnte Sie darauf hinweisen, dass wenn da jemand kleiner 0
eingibt, dass das vielleicht dann zu einem Fehler führen sollte.
Gleiches gilt für den Kreditrahmen.
Auch der ist als größer gleich 0 definiert.
Das heißt auch hier wäre es natürlich sinnvoll, wenn man jetzt testet,
was passiert, wenn einer etwas kleiner 0 eintippt.
Was vielleicht noch auffällt, diese eine Methode hat zwei Parameter
Betrag und Kreditrahmen, aber zusätzlich gibt es hier oben noch diesen
Kontostand.
Dieser Kontostand scheint auch irgendwie wichtig zu sein, wenn Sie
testen wollen, weil der halt eben das Ergebnis so oder so beeinflussen
kann.
Das heißt, Sie müssen sich diese drei Parameter in irgendeiner Form
anschauen und nicht nur die zwei von dieser Methode.
Das heißt, der Zustand dieses Kontos wird halt eben maßgeblich durch
den Kontostand bestimmt.
Ich glaube, das wissen Sie aus Ihrer eigenen Erfahrung.
Ist nicht ganz uninteressant.
Gut, also Eingabe.
Die direkte Eingabe ist eben einmal dieser Betrag und der
Kreditrahmen.
Das heißt, was sich hier anbietet, das sind die Äquivalenzklassen.
Einmal, wir haben hier uns total aus dem Fenster gehen, haben B für
Betrag genommen und KR für Kreditrahmen.
Und einmal soll das Ganze positiv sein, also soll es funktionieren
oder halt eben nicht.
Gut, die gültige Eingabe von dem Betrag ist halt eben dann erreicht,
wenn man größer gleich 0 eintippt.
Das heißt, 0 wäre da wahrscheinlich so eine Zahl, die man testen
wollte.
Ungültige Eingabe von Betrag haben Sie genau dann, wenn Sie etwas
kleiner 0 machen.
Das gleiche gilt dann eben auch beim Kreditrahmen.
Auch der sollte entweder mit Größe gleich 0 getestet werden und einmal
mit kleiner 0.
Das ist schon ein bisschen vorweggenommen.
Auch eine indirekte Eingabe haben Sie.
Das ist halt eben dieser Zustand, dieser Kontostand, der Ihnen da
gegeben wird.
Wir brauchen mal neue Batterien von Presento übrigens.
Ach, zeigt immer leer an.
Gut, dann ist es ein Feature.
Das heißt, wir haben hier drei weitere Äquivalenzklassen.
Vielleicht haben Sie noch weitere gefunden.
Kann ja sein.
Zum einen, Kontostand ohne Kreditrahmen ist groß genug für eine
Abhebung.
Also immer dann, wenn Ihr Kontostand eben größer ist als den Betrag,
den Sie abheben möchten.
Sie haben 1000 Euro drauf, möchten 500 Euro abheben.
Sollte kein Problem sein.
Oder der Kontostand ist nur mit dem Kreditrahmen, den Sie haben, groß
genug für die Abhebung.
Sie haben 1000 drauf, möchten 1500 abheben.
Das geht nur dann, wenn Sie 500 überziehen dürfen.
Also wenn Ihr Kreditrahmen mindestens 500 groß ist.
Also das hier wäre dann ein bisschen formalisiert.
Halt eben genau dieses da.
Oder der Kontostand mit Kreditrahmen ist zu gering für die Abhebung.
Also selbst mit Ihrem Limit, was Sie überziehen dürfen, ist es nicht
möglich abzuheben.
Das wäre dann diese dritte Äquivalenzklasse.
Wir hatten eine Frage.
Wir warten die nächste Folie ab.
Wunderbar, dann habe ich schon mal Angst.
Gut, also das sind die Äquivalenzklassen, die wir hier identifiziert
haben.
Jetzt ging es darum, Sie sollten auch Grenzwerte finden.
Bei Geldbeträgen sind die Grenzwerte wahrscheinlich eher im
Centbereich.
Sie können jetzt auch sagen, Sie testen es mit einem Euro statt mit
einem Cent.
Aber ein Cent wäre eigentlich das naheliegendste, weil das direkt der
erste Wert ist, der eben in dem Fall jetzt größer Null wäre.
Das heißt, von gültigem Betrag und gültigem Kreditrahmen genau dann,
wenn die Größe gleich Null ist.
Das heißt, Null ist diese Grenze, die Sie dort eigentlich haben
möchten, dieser Grenzwert.
Und ungültig ist es halt eben dann genau ein Cent daneben.
Es wäre dann halt eben minus ein Cent jeweils.
Könnte auch ein Euro nehmen, aber das wäre halt eigentlich hier die
korrektere Variante.
Sollte man auch Plus, Minus und Endlich testen bei Big Dezimal?
Da steht die Antwort, ja ist mir egal.
Das ist erstmal ein Test, der überhaupt mitliest.
Wer jetzt sagt, ja und der andere sagt, wollte ich auch sagen, dann
weiß ich die beiden nicht.
Gut, da steht die Antwort natürlich da.
Können Sie nicht testen.
Big Dezimal kann beliebig groß werden.
Sie können auch sagen, wie genau das werden soll.
Dementsprechend ist das in dem Fall nicht.
Wenn Sie jetzt irgendwas testen, was ein Integer oder so als Eingabe
Parameter nimmt, dann will man meistens auch MaxInt oder MinInt oder
irgendwas.
Gibt es MinInt?
Also MaxInt mit Vorzeichen, wunderbar.
Testen oder Null testen, in dem Fall hier nicht.
Null.
Null könnte man testen.
Haben wir gesagt, ja könnte man machen.
Nehmen wir auch an als extra Äquivalenzklasse.
Würden wir aber nicht fordern wollen an der Stelle, weil es hier nur
um numerische Werte geht.
Das ist streng genommen keine Äquivalenzklasse, aber sicherlich ein
sinnvoller Test, den man machen sollte.
Also wenn ich eine Bank wäre, möchte ich so einen Test haben.
Da gebe ich Ihnen auf jeden Fall recht.
Ich versuche Ihnen zu folgen.
Also Sie meinen den zweiten zusammenfassen mit dem da hier?
Ja, aber die Umkehrung gilt ja nicht, oder?
Wenn der Betrag gültig ist und der Kreditrahmen ungültig.
Sie meinen jetzt, also aus inhaltlichen Gründen würde ich Ihnen da
vielleicht recht geben wollen, aus ich lese das Javadoc und möchte
gerne das tun, was im Javadoc steht.
Eher nicht.
Das stört mich an der Stelle ein bisschen, weil im Javadoc steht, es
sollen oder Kreditrahmen soll größer Null sein.
Größer gleich Null und Betrag soll größer gleich Null sein.
Also würde ich erwarten, dass an der Stelle eine Ausnahme ausgelöst
wird oder was auch immer.
Und das würde ich dann eigentlich auch einzeln anschauen wollen.
Für die einzelnen Parameter, das ist das, was im zweiten Schritt dann
passiert.
Also, dass man im Grunde Wertebereiche hat für einzelne Parameter,
sich aber dann zusammen Äquivalenzklassen ergeben.
Aber man kann natürlich auch Äquivalenzklassen für einzelne Parameter
haben.
Sie können natürlich auch da oben sagen, also ja, man könnte das auch
zusammenfassen.
Vielleicht sollte man das auch.
Dann hat man aber noch mehr Äquivalenzklassen.
Dann könnten Sie zum Beispiel prüfen, ob Betrag und Kreditrahmen
gleichzeitig ungültig sind.
Aber dann fallen die Äquivalenzklassen, die wir jetzt haben, nicht
weg, sondern das sind dann einfach nur noch mehr und Sie bauen dann im
Grunde Parameter dazu, die Sie nicht brauchen für den Test.
Also ja, könnte man machen, finde ich aber in dem Fall zu viel.
Also das ist eher schon so die Untergrenze.
Jetzt haben wir zwei Fragen.
Wenn es zu der Folie ist, würde ich die Folie erst vorstellen.
Ansonsten zu einer davor.
Gut, ich blättere.
Ja, ja, ich verstehe, was Sie meinen.
Also es ist entweder gültig oder nicht, weil entweder kann ich mein
Konto belasten oder nicht.
Es gibt nur diese zwei Möglichkeiten.
Ja, schon, aber es gibt ja zwei Parameter, die das beeinflussen.
Und deshalb möchte man da schon eine extra Äquivalenzklasse haben,
weil Sie ja testen möchten, wie das Programm sich verhält.
Es könnte ja sein, dass die Implementierung den Kreditrahmen
ignoriert.
Wenn Sie dann nur den einen Test machen mit Betrag positiv, weil das
ist ja alles gut, Kreditrahmen ignorieren, weil brauchen wir nicht,
ist ja gleiche Äquivalenzklasse.
Dann haben Sie an der Stelle einen Test zu wenig.
Nämlich der, den der Kreditrahmen mit betrachtet.
Nee, nee, nee, deshalb variieren wir ja die Äquivalenzklassen über die
Eingabe -Parameter.
Wir wissen, dass Kreditrahmen und Betrag und der ursprüngliche
Kontostand einen Einfluss haben.
Also versuchen wir, diese drei Sachen so zu variieren, dass sie
gemeinsam in unterschiedlichen Bereichen landen.
Das ist das, was wir jetzt gleich hier auf diesem auf diesem Strahl
sehen.
Und das erreichen Sie nicht, wenn Sie nur die zwei Äquivalenzklassen
bilden.
Das ist halt das Problem, was da entsteht.
Da verdecken Sie im Grunde den Kreditrahmen oder können den
Kreditrahmen nicht mehr unabhängig von dem absehbenden Betrag testen.
Also Sie übersehen dann gegebenenfalls einen Fehler.
Eine Frage?
Ja, ja, ja.
Also Ihr Kommilitone beschwert sich, ist ein bisschen schwammig auf
den Folien zur Vorlesung.
Bin ich fast geneigt, Ihnen recht zu geben.
Die sind sicherlich nicht optimal.
Deshalb haben wir versucht, extra so ein greifbares Beispiel zu
nehmen, was jeder schon mal hatte im roten Bereich des Kontos.
Und trotzdem konnte man noch Geld abheben.
Ja, die sind da vielleicht nicht genau genug.
Vielleicht muss man das mal noch ein bisschen klarer machen.
Ist uns jetzt in den letzten zwei Wochen auch aufgefallen, dass das,
was wir mit sehr viel Wissen über den ganzen Kram unter
Äquivalenzklassen verstehen, vielleicht Ihnen durch die Vorlesung
nicht genügend klar geworden ist.
Also ja, könnte tatsächlich sein.
Werden wir auf jeden Fall noch mal anschauen und gegebenenfalls die
Folien anpassen.
Sehe ich nämlich ähnlich.
Okay, sonst noch Fragen?
Da ist noch eine Frage.
Die ersten drei, warum die getrennt sind, oder?
Genau, genau.
Das ist jetzt wieder das, was ich gerade eben schon mit Ihrem
Kommilitonen diskutiert habe.
Also die Kommilitonin merkt an, ja, da haben wir jetzt auch keine
sinnvollen Äquivalenzklassen, weil mein Argument, was ich gerade
gebracht habe, man soll doch bitte die Parameter in Kombination
testen, geht ja da verloren.
Da haben sie ein Stück weit recht.
Man müsste hier eigentlich auch die Kombination bauen, aber dann
fallen die halt wieder zusammen und am Ende bleibt das im Wesentlichen
übrig, weil wir können hier natürlich sagen, wir haben eine ungültige
Eingabe von Betrag und dazu die gültige Eingabe von Kreditrahmen und
dann haben wir noch eine weitere Äquivalenzklasse mit ungültiger
Eingabe von Betrag und ungültige Eingabe von Kreditrahmen, aber die
fallen dann halt eigentlich wieder zusammen.
Deshalb haben wir die weggelassen.
Aber eigentlich haben sie recht, sollte man das so machen.
Sollte man eigentlich sämtliche Kombinationen bauen.
Das ist jetzt eher schon das Zusammengeschobene.
Die Klasse von Fehler ist die gleiche, weil der Fehler eben die
ungültige Eingabe von Betrag ist, aber natürlich sind es mehrere
verschiedene Kombinationen, die dadurch möglich sind, weil die anderen
beiden Parameter egal sind.
Weitere Fragen noch?
Dann spreche ich mal zu dieser schönen Zahlenstrahlfolie.
Ich habe versucht, das Ganze mal ein bisschen zu visualisieren.
Also das hier soll der Kontostand darstellen, KS.
Hier wäre er schön im Plus-Bereich, hier ist er im Minus-Bereich.
Im Endeffekt lässt sich das Ganze so ein bisschen in drei Teile
einteilen.
Zum einen Kontostand ohne Kreditrahmen ist groß genug für die
Abhebung.
Das wäre hier dieser Teil.
Also wenn ich da etwas abheben möchte, dann bin ich immer noch im Plus
-Bereich.
Also das reicht aus.
Dann dieser zweite Fall.
Der Kontostand ist nur mit dem Kreditrahmen groß genug für die
Abhebung.
Das heißt, ich falle unter Null, aber ich habe hier diesen
Kreditrahmen.
Und mit diesem Kreditrahmen, den kann ich ausschöpfen bis zu dem
Rahmen an sich, bis zu der Linie an sich.
Das ist so die zweite Klasse.
Und dann gibt es halt eben noch die, es reicht nicht.
Also selbst wenn ich das Konto überziehe und bis zum Kreditrahmen
gehe, reicht es immer noch nicht.
Ich wäre noch weiter im Minus.
Was Sie hier aber sehen, wenn Sie jetzt testen wollen, Sie möchten die
Grenzen testen.
Also Sie haben irgendwelche Werte bestimmt und sagen, okay die Null
scheint ja wichtig zu sein.
Das jetzt testen mit einem Cent oder mit minus einem Cent.
Sie sehen, wenn Sie eben auf die eine Klasse eins draufhauen oder
wegnehmen, dann rutschen Sie in die andere Klasse.
Das heißt, Sie haben hier einen Überlapp, weil eben die eine
Äquivalenzklasse nahtlos an die andere anschließt.
Das heißt, wenn Sie Tests bauen, würden Sie die Tests bauen, dass Sie
die eben jenseits dieser Trennungen von diesen Äquivalenzklassen bauen
würden.
Genau.
Und auch hier nochmal der Hinweis, eigentlich müsste natürlich da oben
die Äquivalenzklasse heißen, Kontostand positiv, also Betrag größer
Kontostand und Kreditrahmen gültig.
So müsste es eigentlich sein, weil wir eigentlich noch den dritten
Parameter auch mit testen müssen.
Aber das haben wir jetzt hier weggelassen, weil das ist halt da die
Voraussetzung.
Aber eigentlich wäre das so.
Und dann wäre wieder die Umkehrung davon.
Wir variieren den dritten Parameter mit Kreditrahmen ungültig, aber
dann fallen wir wieder in die Äquivalenzklasse mit Kreditrahmen ist
ungültig und das wirft hoffentlich eh immer einen Fehler.
Deshalb haben wir das jetzt hier nicht nochmal mit drin.
Aber eigentlich müsste man natürlich alle einzelnen Parameter
miteinander in allen möglichen Varianten kombinieren, die
Äquivalenzklassen zu bekommen.
Haben Sie noch Fragen zu dieser Aufgabe?
Ja, nein, vielleicht.
Wird noch diskutiert.
Dann kommen wir zu dem Moment, auf den ich mich schon das ganze
Semester über freue.
Zum kontrollflussorientierten Testen.
Das ist ein Testverfahren, was sehr genau Aufschluss darüber gibt, ob
man alles, was man hätte testen können für einen gewissen
Programmausschnitt, meistens Methoden, auch tatsächlich getestet hat.
Und es ist was, worauf bei uns auch in der Vorlesung relativ viel
großen Wert gelegt wird.
Wenn Sie schon Eiklausuren angeschaut haben, werden Sie gesehen haben,
dieses kontrollflussorientierte Testen kommt irgendwie immer vor in
der Klausur.
Deshalb wollen wir das jetzt hier in der Übung auch nochmal relativ
ausführlich machen.
Was muss man oder könnte man tun, wenn man kontrollflussorientiert
testet von Hand?
Dann möchte man vielleicht den Quelltext in Zwischensprache
überführen.
Ich mache das selber nicht.
Ich baue das immer direkt aus dem Code, ohne die Zwischensprache.
Aber am Anfang zur Übung ist das eine tatsächlich gute Variante.
Deshalb führen wir das in der Vorlesung so ein.
Und so die ersten drei, vier, fünf Kontrollflussgrafen, die Sie bauen,
zur Übung würde ich Ihnen auch echt empfehlen, über die
Zwischensprache zu machen, weil die ansonsten einfach Dinge vergessen
oder erstmal grundsätzlich nicht wissen, wie man so eine Schleife
auflöst.
Gut.
Dann fangen nämlich so Dinge an, wie man braucht ja dann irgendwie
diese Sprungziele, die ergeben sich.
Man muss sich überlegen, wie groß sind denn eigentlich die Blöcke,
wann hören die auf?
Und am Ende, wenn man das Ganze fertig gebaut hat, gibt es noch so ein
paar Prüfkriterien, die man noch mal anlegen sollte an seine eigene
Lösung.
Und das ist so was wie, gibt es Pfeile, die in die Mitte eines Blockes
zeigen, dann sollte man wohl davor aufteilen, weil ein Pfeil kann
niemals in die Mitte von einem Block gehen beim Kontrollflussgrafen,
sondern die fangen immer oben an.
Dann nächster Test.
Gibt es leere Blöcke, dann kann man offensichtlich verschmelzen.
Und gibt es irgendwo unbedingte Sprünge, dann kann man gegebenenfalls
Knoten verschmelzen.
Es sei denn, man kommt dann wieder irgendwo mit einem anderen Sprung
in die Mitte von einem Block rein.
Also das Eins und Drei bei diesen Prüfkriterien widersprechen sich
ganz gerne mal.
Also da aufpassen.
Wir sehen das jedes Jahr wieder in der Klausur, dass irgendwie Sprünge
in die Mitte von Blöcken reingehen und dann denkt man sich, das ist
doch eigentlich das einfachste und offensichtlichste, was nie
passieren darf.
Denken Sie da dran.
Auch beim Üben jetzt schon.
Und weil ich ja versuche, mich immer ganz gerne in die Leiden von
Studenten reinzuversetzen.
Ich habe nicht gesagt, dass ich das dann vorher erzeugt habe.
Ja, das ist genau das Leid, was ich vorher erzeugt habe.
In das versuche ich, mich ganz gerne reinzuversetzen.
Und aus diesem Grund versuche ich jetzt mal, diesen KfG von Hand zu
zeichnen.
Jetzt hier live und in Farbe.
Das war die Aufgabe.
Das war ein Ausschnitt aus unserer Identitätsberechnung, ein bisschen
abgewandelt, damit es ein bisschen handlicher ist.
Dann konnte man da auch relativ schnell und hoffentlich einfach einen
KfG daraus bauen.
Wichtig ist, wenn Sie sowas sehen bei der Klausur, wie diese ewig
lange Bedingung da.
Sie werden in der Klausur keine Zeit dafür haben, das komplett
aufzuschreiben.
Kürzen Sie es ab, aber kürzen Sie es bitte sinnvoll ab und eindeutig.
Häufiger haben wir auch mal Sysouts drin für gewisse
Programmausschnitte.
Auch da gilt das gleiche.
Sinnvoll abkürzen, aber so, dass es bitte noch eindeutig bleibt.
Also bitte unterscheidbar.
Wenn es zwei Sysouts gibt und Sie sagen nur Sysout A und B und wir
können es da nicht zuordnen, welches Sysout Sie jetzt wo gemeint
haben, dann können wir das nicht bewerten.
Also bitte so abkürzen, dass es eindeutig ist, welches Sysout.
Und vor allem auch zuordnenbar noch zum Code ist.
Ja, klar.
Genau.
So, da gibt es schon mal zwei Fragen.
Bevor ich überhaupt angefangen habe, besonders schön.
Dann fangen wir bei Ihnen mal an.
Okay, der Kommilitone fragt, ob es sinnvoll ist, die Zwischensprache
zu benutzen in der Klausur.
Kurze Antwort, nein.
Ich würde es nicht machen.
Ich würde es vorher zur Übung machen.
Das ist mein persönlicher Tipp.
Und so viel Sicherheit erlangen vorher schon, dass ich es dann in der
Klausur direkt vom Code kann.
Weil ich glaube, das verbraucht zu viel Zeit.
Wir sehen das jedes Jahr wieder, dass das vereinzelt Studenten machen.
Ich halte es für keine gute Idee.
Dieses Jahr haben wir eine halbe Stunde mehr Zeit in der Klausur.
Vielleicht ist es dann nicht mehr so kritisch, aber ich glaube, die
halbe Stunde kann man auch woanders besser verbrennen.
Insofern, ich würde es nicht machen.
Noch eine Frage?
Also, Ihr Kommilitone fragt, dürfte man auch die Zeilennummern
verwenden?
Und egoistisch, wie ich bin, sage ich nein.
Weil das spart Ihnen einen Haufen Zeit.
Das bereitet mir aber extrem viel Schmerzen beim Korrigieren.
Insofern, sorry, machen wir nicht.
Sie dürfen gerne abkürzen, so viel Sie wollen, solange es
übersichtlich und lesbar bleibt.
Aber es lässt sich halt nicht mehr korrigieren, wenn da halt nur noch
1, 2, 3, 4, 5 in den Kästchen drin steht und ich jedes Mal wieder
rüberschauen muss, war das jetzt das Return?
War das jetzt hier die Zuweisung?
Davon abgesehen funktioniert das nicht.
Dazu müssten Sie die Zwischensprache bauen, damit das funktioniert und
dann auf die Zwischensprache verweisen und die durchnummerieren.
Weil wenn Sie mal in Seite 7 umschauen, das werden drei Zeilen.
Das könnte schwierig werden.
Da noch eine Frage?
Ihr Kommilitone fragt, ja, kann ich nicht einfach da Blöcke zeichnen
und die dann nummerieren?
Tatsächlich habe ich gestern versucht, in diesen Code den KFG rein zu
zeichnen.
Das wäre so eine ähnliche Idee.
Machen Sie es nicht.
Keine gute Idee.
Ich habe dann spätestens bei der zweiten Vorschleife habe ich dann
aufgehört, weil es funktioniert nicht.
Gut.
Noch Fragen zu den technischen Feinheiten des KFG-Zeichnens?
Nein?
Okay.
Dann jetzt viel Spaß mit meiner unleserlichen Schrift.
Wir versuchen das jetzt mal hier live.
Yay.
Das funktioniert soweit schon mal ganz gut.
Der Fokus passt auch.
Ich habe da oben noch mal den Code abgedruckt, damit wir ab und zu mal
nach und nach hochspringen können, während ich hier zeichne.
Und ich habe natürlich die Mussel-Lösung neben mir liegen, weil ich
mache hier nichts ohne Netz und doppelten Boden.
Ich will mich ja hier auch nicht blamieren.
Dementsprechend, ja, Martin guckt schon erwartungsvoll, dass das doch
passiert.
Wie viel Zeit habe ich denn eigentlich noch?
Ich sollte mich beeilen.
Also vielleicht mache ich auch nur den Anfang live, weil der spannende
Teil kommt ehrlich gesagt nur am Anfang.
Und da möchte ich auch mal sehen, ob Sie das schon wissen, kennen,
verstanden haben.
Also, wie fangen wir denn an?
Wir haben hier irgendwie so eine Eingabe und die Eingabe ist bei uns
eine Double Matrix.
Ja, schon habe ich hier meinen ersten Block fertig und dem gebe ich
jetzt noch einen Namen.
Bitte, bitte nicht vergessen in der Klausur.
Wir fragen fast immer, was sind dann irgendwie durchlaufende Pfade,
wenn wir Anweisungsüberdeckung oder so ähnlich machen wollen.
Wir haben jedes Jahr wieder Abgaben ohne Nummern an den Blöcken und
dann stehen da irgendwelche Testpfade und man denkt sich ja, wo gehört
das jetzt dazu?
Gut, da kommt gleich die erste Frage.
Ich habe noch nicht mal einen Block fertig gemalt, aber bitte?
Also Zustände gibt es schon mal gar nicht.
Es gibt, wenn, dann gibt es Blöcke.
Bitte, was?
Ja,
das ist ja das, was ich hier auch gemacht habe.
Ich habe das bloß ein bisschen größer ausgeführt.
Das ist Endstart da oben.
Das sind nicht zwei genau, also meine Beschriftungsart ist immer so,
dass ich da so kleine Kästchen oben dran schreibe, weil dann bin ich
flexibler mit dem Zeichnen.
Wir können das natürlich auch so hier reinschreiben, ja.
Endstart, Doppelpunkt.
Ja, klar.
Also uns gerade egal.
Ich könnte es jetzt nicht mehr lesen, gebe jetzt Abzug in der Klausur.
Ich auch nicht, aber... So, jetzt kommt gleich der erste spannende
Punkt.
Was mache ich denn mit dem If mit dieser Bedingung?
Wie mache ich das richtig?
Da meldet sich jemand.
Zwei Blöcke, bitte.
Also, wir müssen zwei Blöcke jetzt bauen.
Also wir haben einmal hier das If mit der Matrix gleich null.
Das ist jetzt der erste Teil, ja.
Da haben wir jetzt den 1.
So, und das teilen wir jetzt auf und bauen jetzt noch den zweiten Teil
des eigentlichen Codes.
Was war das?
Blank.
Ungleich.
Hätte man nicht eigentlich einen einfachen Code nehmen können hier zum
zeigen?
Nein, gell?
Wer hat denn diese Aufgabe gebaut?
Immerhin war es der, der es jetzt auch ausbaden muss.
So.
Könnte ich ja zeigen, wie man geschickt abkürzt.
Ja, ich habe das jetzt gerade wunderbar nicht getan.
Ja.
Also so machen sie es bitte nicht in der Klausur.
Das kann man zum Beispiel machen als Zeichen für falsch.
Fände ich völlig okay.
Und dann entsprechend, also wir bräuchten jetzt hier oben noch den,
was dann passiert im Block.
Nämlich das return false.
Das wäre bei uns hier in 3.
Ich würde ja echt Abzug machen hier mit deiner Sauklaue, ne?
Ach, Martin.
Du weißt genau, dass das nicht stimmt.
Dass du das sagst.
Genau, ich würde dir was abziehen.
Aber ja.
Also Martin würde das nie machen, weil Martin ist der netteste von uns
dreien im Übungsleiterkreis.
Dementsprechend würde er es nie tun.
Er würde eher noch mit der Lupe rangehen und versuchen, das doch noch
zu verstehen.
Gut.
Und hier unten geht es dann halt entsprechend weiter wieder mit, was
ist, wenn das nicht ist.
Ich würde jetzt mal hier kurz pausieren und noch mal fragen, warum
muss ich das denn bei der Kurzschlussauswertung hier aufteilen?
Ich weiß, wir legen da seit einigen Jahren Wert drauf und wir sehen
das immer schön in den Altklausuren und Sie lernen das bestimmt alle
schön auswendig.
Aber warum muss man das denn tun?
Komm, die Tone meldet sich.
Genau.
Also bei der Kurzschlussauswertung haben wir das Problem, dass der
rechte Teil gegebenenfalls überhaupt angeschaut wird.
Und da könnte ja auch tatsächlich eine Zuweisung drin passieren.
Es gibt einen ganzen Methodenaufruf oder whatever könnte passieren.
Dementsprechend muss man das aufteilen, weil sich einfach die
Anweisungsüberdeckung ändert, wenn man das nicht tun würde.
Da kommt noch eine Anmerkung.
Also Ihr Kommentator fragt, ja, in der Zwischensprache wird das doch
immer umgedreht.
Warum ist das jetzt hier nicht der Fall?
Das können Sie gerne machen.
Da haben wir nichts dagegen.
Wenn Sie zum Beispiel mit der Zwischensprache geübt haben, die
Bedingungen umdrehen, um dann den Kontrollflussgrafen zu bauen mit den
umgedrehten Bedingungen, dann müssen Sie natürlich gerade die
Umgekehrten an die Kanten schreiben.
Man kann es aber auch so machen.
Es ist uns persönlich völlig egal.
Ich mache es lieber so, weil das ist näher am Code.
Ich kann es dann besser kontrollieren.
Ich habe mich auch mal gefragt, warum machen wir das eigentlich in der
Zwischensprache?
Es gibt allerdings vereinzelt Fälle, wo es nicht funktioniert, wegen
den Sprungbefehlen, wenn man die Bedingungen nicht umkehrt.
Ich nagele mich jetzt nicht mehr fest, was das war, aber ich habe da
auch schon mal dran gezweifelt, ob das überhaupt nötig ist.
Aber leider ist es das tatsächlich.
Also wenn man die Zwischensprache benutzt, dann muss man es
tatsächlich tun.
Aber wie gesagt, ich würde die Zwischensprache eh nur zum Üben, zum
Reinkommen benutzen und dann direkt am Code und mit den normalen
Bedingungen arbeiten, weil dann ist es einfach auch nachvollziehbar,
wie es denn im Code abläuft und wie es im KFG abläuft.
Okay, sonst noch Fragen bis hierher?
Noch eine Frage, wunderbar.
So, genau, sehr schön.
Das wäre das Nächste, was ich hätte erklären wollen.
Könnte man nicht aus diesem einen return false einen Block machen ganz
am Ende und dann hat man halt nur noch einen, statt den jetzt
irgendwie, wie ist es in unserer Musterlösung, dreimal zu zeichnen.
Hat da jemand eine Meinung dazu, ob das eine gute Idee ist?
Ach komm, die sitzen direkt neben dran.
Ja, ich danke für diese perfekte Antwort.
Also, ihr Kommilitone direkt nebendran.
Erklärt Ihnen das vollkommen richtig, Sie hätten einfach mal nach
links fragen müssen.
Also, es ist die vollkommen richtige Antwort.
Also, das Problem ist, es sieht jetzt irgendwie so aus, als wäre das
redundant.
Ich zeige mal, ich ende mal ganz kurz hier unsere finale Lösung ein.
Ja, also wir haben hier irgendwie dreimal return false, aber brauchen
wir auch alle, weil wenn wir jetzt wieder mal zurück, eigentlich ist
das witzig hier, zurück in den Code schauen, dann haben wir die an
unterschiedlichen Stellen stehen.
Was wir erreichen wollen mit diesen kontrollflussorientierten Testen
ist, zum Beispiel anschauen, haben wir alle Anweisungen angeschaut.
Da können wir nicht sagen, okay, wir haben einmal in return false
gesehen, wir haben sie alle gesehen.
Ja, das funktioniert halt leider nicht.
Also, nicht zusammenziehen von irgendwie return false Geschichten.
Gut.
Und noch Fragen?
Ja, sie wollen ja wissen, ob sie, genau, also ihr Kommilitone sagt,
ja, aber es ist doch trotzdem irgendwie das gleiche in der Praxis.
Nee, also sie wollen ja schon wissen, ob sie in diesen Block überhaupt
reinkommen.
Ja, es kann ja irgendwas in der Bedingung falsch sein.
Ja, genau.
Also und spätestens, wenn es dann an die Zweigüberdeckung geht, hört
es dann halt auf zu funktionieren, weil sie dann schon wissen, kommen
sie auch über alle Zweige zum return, zu dem jeweiligen return.
Okay, noch Fragen, Wünsche, Anmerkungen?
Ich glaube, ich würde ansonsten mal mit den Folien weitermachen, weil
ich glaube, wenn ich hier zeichne, dauert es dann doch zu lang.
Ich überlege gerade, gibt es noch irgendeinen spannenden Fall in der
Aufgabe?
Eine Vorschleife noch.
Ach ja, genau.
Du meinst, damit man mal gesehen hat, wie man so eine Vorschleife
aufbaut, auflöst.
Okay, gut.
Dann machen wir an der Stelle mal noch weiter.
Also, wir hätten hier im Code als Nächstes erstmal diese Zuweisung mit
dem Integer.
Ja, die machen wir mal als Nächstes.
Wir bauen also hier wieder einen Block.
Wir machen int n, Punkt, Punkt, Punkt.
So, und mit meiner großen Erfahrung im KFG-Zeichnen weiß ich jetzt,
hier kommt eine Vorschleife.
Und das ist jetzt genau der Grund, machen Sie das nicht mit den
Vorschleifen und Zeilnummern und bauen Sie da Blöcke und üben Sie es
vor allem auch einmal mit der Zwischensprache, weil das sieht man nur,
wenn man es schon ein paar Mal gemacht hat.
Diese Laufvariable der Schleife, in dem Fall ist das hier r, die muss
ich ja auch erstmal anlegen.
Also, ich kann jetzt hier gleich int r gleich 0 anlegen.
Und das ist in einem Block mit dem davor, obwohl dann eine Schleife
anfängt.
Ja, das r wird nur einmal angelegt, deshalb kann ich das da mit in den
Block machen.
Das wird also hier mein Block n4.
Genau, n4.
So, wunderbar.
Und jetzt kann ich im Grunde die Schleifenvariable prüfen als
Nächstes.
Das heißt, wieder Zwischensprache gelernt.
Ich mache aus Schleifen ein if mit einem Sprungbefehl.
Und hier kommt jetzt erstmal in mein n5 eine Bedingung.
Was mache ich jetzt mit dem Sprungbefehl?
Also, wir machen jetzt, hier wird es weitergehen, was auch immer
passiert.
Und irgendwo haben wir dann unser, in unserem Fall wäre das jetzt
tatsächlich n14 gewesen.
Also, es sind ein paar Blöcke.
Und da ist dann unser r++.
Das heißt, das passiert irgendwo... das war natürlich jetzt Käse,
gell?
Ah, live ist immer doof.
So, genau.
Auf dem Overhead ist es noch schöner.
Irgendwann haben wir dann halt unser r++ am Ende der Schleife.
Und dann springen wir natürlich von dort aus wieder zurück an diese
Stelle.
Und da sehen wir jetzt auch genau, wir haben den Einspruchspunkt bei
der Bedingung und eben nicht bei der initialen Zuweisung von dem r.
Deshalb können wir das r mit in den Block davor ziehen.
Gut, das war noch der spannende Teil.
Gibt es noch was Spannendes in der Aufgabe?
Ich glaube nicht.
Ansonsten schauen wir jetzt einfach mal auf die Lösung.
Wir haben auch noch mal die Zwischensprache mitgebracht, wer sich das
tatsächlich reinziehen will.
Was halt schön ist, man sieht dann halt sehr gut die Sprünge.
Man sieht genau das, worauf ich hingewiesen habe, dass das r
unabhängig ist von der eigentlichen Schleife, dass das einmal vorher
angelegt wird.
Wir sehen wunderbar hier unten, dass das r++ ganz am Ende passiert.
Wir sehen hier dieses goto7, was am Ende die Kante wird.
Also, es ist schon sehr übersichtlich, das damit zu machen, aber wie
gesagt, machen Sie es lieber nur zur Übung.
Frage?
Ja.
Also, Ihr Kommilitone fragt, ob, wenn wir jetzt ein if haben, an das
später nicht zurückgesprungen wird, ob das in einen extra Block kommt
oder ob das mit dem Block, der davor kommt, verschmolzen wird.
Und die Frage gebe ich jetzt einfach mal an Sie zurück.
Was meinen Sie denn?
So, Ihr Kommilitone meint, es sollte mit dem Block dazukommen.
Damit hat er recht.
Und jetzt sagt er mir noch, warum er damit recht hat.
Gemein heute, gell?
Muss man seine Fragen selber beantworten.
Es wäre konsistent, ist mir ein bisschen zu einfach.
Sie haben eine bessere Meinung?
Genau.
Also, Ihr Kommilitone meint, die Definition von Block ist, der endet
dann, wenn ein Sprungbefehl passiert und der passiert danach.
Und wir haben auch keinen, wie Sie gesagt haben, mehr, der davor
zurückspringt, also vor das if.
Deshalb kann man es zusammenziehen.
Okay, also Ihr Kommilitone meint, er hätte es in Altklausuren anders
gesehen.
Wenn Sie meinen, dass da ein Fehler in der Altklausur ist, gerne bei
uns melden.
Gerne mit Ihrer Klausur, sagen wir, Semester 2009, Aufgabe 14 ist ein
Fehler.
Oder da ist irgendwas komisch.
Ich verstehe es nicht.
Gerne im Forum melden, sagen, fragen.
Kann ich jetzt von hier aus nicht beurteilen.
Genau, den haben wir halt im Zwischencode, sehen wir den.
Den Stop Block, den kann man zusammenfassen.
Also Sie brauchen nicht für jedes Return einen eigenen Stop Block.
Der Stop ist ja im Grunde nur ein Platzhalter für, hier sind wir jetzt
am Ende unseres Testverfahrens.
Den gibt es ja im Code eigentlich nicht.
Also schauen wir einfach mal an, wie die Musterlösung aussehen würde.
Den Teil da oben, ich erkläre das mal ganz kurz noch.
Also das ist der Teil, den wir da oben gesehen haben.
Bis hierhin hatte ich Ihnen das gezeigt.
Und der Rest, der funktioniert analog.
Ich meine, das sind auch immer nur noch, hier war nochmal ein if, hier
ist nochmal eine Schleife, hier ist nochmal ein if mit einem Sprung.
Alles nicht so furchtbar spannend.
Man sollte halt keinen echten Code nehmen für Kontrollflussgraphen.
Das wird häufig ein bisschen unspannend.
Naja, also das würde rauskommen am Ende.
Ist wie gesagt, der spannende Teil ist einmal das hier oben und dann
einmal eine Schleife auflösen.
Alles andere funktioniert eigentlich analog.
So, jetzt zu Ihrer Frage bitte.
Ihr Kommentator möchte wissen, ist es wichtig, ob die Dinger
abgerundet oder eckig sind?
Ich würde da gerne Wert drauf legen, aber die Erfahrung sagt mir, ich
bin froh, wenn ich überhaupt was erkennen kann in der Klausur, was
dahin geschmiert wurde.
Nee, also ist uns relativ egal, wie das aussieht.
Solange es...
Bitte?
Genau, bei anderen Diagrammen ist das wichtig.
Bei UML-Diagrammen kann das wichtig sein, weil das teilweise einen
semantischen Unterschied macht, ob die eckig sind oder rund.
Hier hätte ich es gerne eckig, aber ganz ehrlich, wenn es nicht eckig
wird und wenn es rum und schief wird, Hauptsache, ich kann es lesen
und eindeutig zuordnen.
Also, ja.
Geben Sie sich Mühe beim Zeichnen, aber ob das jetzt eine runde Ecke
ist oder eine eckige Ecke, mir gerade egal.
Okay, noch Fragen dazu?
Ja?
Nee, aber die Zwischensprache, also die Kommilitone fragt, stopp,
Block in der Zwischensprache.
Nein, muss nicht und ist mir auch ehrlich gesagt völlig egal.
Selbst wenn sie die Zwischensprache machen, gucke ich mir die nicht
an.
Okay.
Kommilitone fragt, gibt es eine eindeutige einheitliche Nominierung
der Blöcke?
Die richtige Antwort ist, so wie in der Musterlösung, weil nur dann
können wir es korrigieren.
Nein.
Also, es ist natürlich schön, wenn das irgendwie korrespondiert mit
der Reihenfolge, wie es im Code vorkommt.
Das geht natürlich nicht immer eins zu eins, sondern es gibt einfach
Unterschiede.
Wir werden das sicherlich nicht mit Abzügen belegen.
Also ja, das ist im Wesentlichen künstlerische Freiheit.
Sie tun uns beim Korrigieren großen Gefallen, wenn Sie das irgendwie
versuchen, fortlaufend zu machen.
Aber wenn Sie mit N42 rückwärtszählend anfangen, kann ich Sie dafür
auch nicht bestrafen.
Glaube ich.
Ich muss aber meinen Chef fragen, was der dazu sagt, aber ich glaube
nicht.
Also kann man machen.
Noch Fragen?
Sonst komme ich ja gar nicht hin, mir dazu noch die Ewald
vorzustellen.
Gut, es war noch gefragt, wie sind denn jetzt eigentlich die
durchlaufenden Pfade für, was wollen wir machen,
Anweisungsüberdeckung.
Also jede Anweisung mal gesehen haben.
Welche Testfälle muss man da eingeben?
Das fragen wir auch ganz gerne mal in Klausuren.
Und zwar fragen wir immer nach der minimalen Testfallmenge.
Also man könnte ja dann noch 15 machen.
Oder manchmal ist es auch so, dass einem irgendwie ein Testfall
einfällt.
Mit dem geht das dann ganz schnell.
Und man läuft so ein paar Anweisungen ab und dann braucht man halt
noch fünf andere.
Aber eigentlich hätte es drei gegeben, mit denen es auch funktioniert
hätte.
Das heißt, immer versuchen, die minimale Testfallmenge zu finden.
Das heißt, Mengen von diesen Eingaben.
Ihr Kommilitone hat eine Frage?
Okay.
Ihr Kommilitone fragt, haben wir bei P1 nicht Freiheitsgrade, was die
Eingabe betrifft?
Könnte das nicht entweder null sein oder das andere, um auf den ersten
Return -Block zu kommen?
Ja.
Genau, das ist jetzt genau das Problem.
Wenn Sie null benutzen würden, würden Sie an der Stelle den Block 2
verpassen.
Aber den sehen wir eh noch in anderen Fällen.
Also Sie könnten da oben auch null benutzen.
Wäre völlig okay.
Könnten Sie machen, weil wir haben ja hier eh den Block 2 noch
abgedeckt.
Das ist nämlich genau der, der die zweite Bedingung prüft.
Insofern, könnten Sie auch anders bauen.
Noch Fragen?
Ihr Kommilitone fragt, ich sitze in der Klausur und bin mir nicht
sicher, ob das die minimale Testfallmenge ist.
Wie kann ich das denn prüfen?
Ganz ehrlich, da habe ich kein Kochrezept dazu.
Was ich Ihnen aber sagen kann, ist das, was ich gerade eben gesagt
habe.
Man fängt mal mit irgendwas an, mit irgendeiner Eingabe, die einem
einfällt und macht dann weiter.
Das ist im Allgemeinen eine schlechte Idee.
Versuchen Sie sowas zu machen, wie Äquivalenzklassen bilden.
Also schauen Sie sich die Bedingungen an, die hier vorkommen und
überlegen Sie sich, was kann man denn hier, wie variieren.
So kommt man am schnellsten auf die Eingabemengen und die sind dann
auch im Normalfall dann schon minimal, weil man sich daher überlegt
hat, wird es entweder so oder so und hat nicht irgendwas zufällig
gewählt.
Da muss man manchmal noch ein bisschen scharf hingucken.
Aber mehr kann ich dazu tatsächlich nicht sagen.
In diesem Fall möchten Sie auch jeden Returnblock einmal treffen.
Das heißt, Sie würden auch schauen, wenn Sie zu diesem Returnblock
kommen.
Ja, davon noch abgesehen, wenn Ihre Testvermengung nicht minimal ist,
da gibt es dafür dann auch nur einen minimalen Abzug.
Gut.
Ja, sorry, noch eine Frage.
Ja, genau.
Ihr Kommilitone fragt, ja, hier sind so geschweifelte Klammern für die
Matrizen.
Wäre uns völlig egal.
Ich mache mal einen kurzen Spoiler.
Wir werden sowas garantiert nicht in der Klausur drannehmen, weil das
ergibt genau zu viele Fights gerade.
Also wenn da jemand anfängt, Matrizen hinzuzeichnen als Eingabe, habe
ich da keine Lust, das zu korrigieren in der Klausur.
Das dürfen die Tutoren im Übungsbetrieb machen.
Dementsprechend verlassen sie sich darauf, dass das irgendwie ziemlich
einfach sein wird, was man da in Eingabe liefern kann.
Aber ja, jetzt für den Übungsbetrieb haben wir auch im Forum
beantwortet mit wahnsinnigen in Ordnung.
Noch Fragen?
Ja.
Sie können aufhören zu fragen, ich erkläre es Ihnen.
Also Ihr Kommilitone möchte wissen, wenn ich einen falschen Graphen
gemalt habe und dann baue ich eine Testvermenge dazu, wird es dann
trotzdem noch bewertet in der Klausur, richtig?
Das wäre Ihre Frage gewesen.
Ob das als Folgefehler zählt?
Ja, die Antwort ist wie immer ein ganz klares Jein.
Wir versuchen natürlich Folgefehler zu berücksichtigen und werden uns
oder schauen uns immer dann auch die durchlaufenden Pfade für kaputte
Graphen an, auf alle Fälle.
Es gibt allerdings eine Ausnahme und das ist, wenn Sie den Graphen so
einfach bauen, dass Sie zum Beispiel nur noch einen...ja, genau.
Sie lachen, aber das kommt häufiger vor, als Sie denken.
Und wo die Schwelle liegt, das kann ich Ihnen jetzt nicht sagen.
Also das wird bei uns dann während der Korrektur im Kollegenkreis
festgelegt.
Also der Graph da, das ist zu einfach, da können wir keine Punkte mehr
drauf geben.
Also wenn man zum Beispiel irgendwie vier Tests braucht, um da
durchzukommen und man sich echt Gedanken machen muss, welche vier
Testeingaben das sind, um dann Anweisungsüberdeckung hinzubekommen.
Und Sie bauen einen Graph, der vielleicht nur drei, vier Kanten
weniger hat und man braucht am Ende nur noch einen Testfall, der auch
noch trivial ist, dann sind Sie leider raus an der Stelle.
Aber ansonsten, wenn dann nur ein Block falsch ist und dadurch das
irgendwie leicht anders ist, gucken wir uns auf jeden Fall an.
Dann gibt es Abzug auf den KfG, aber normale Punkte auf
Anweisungszweig oder was auch immer Überdeckung.
Gut, noch Fragen?
Wollen alle gar nicht die Eval-Ergebnisse wissen, oder?
Ich glaube, die zögern das raus heute, ja.
Okay, ich glaube, es geht einfach auf die Klausur zu und die Leute
haben sich mit dem Stoff beschäftigt und plötzlich kommen die Fragen.
Damit konnten wir nicht rechnen.
Ja, genau, dass sich tatsächlich mal jemand mit dem Stoff beschäftigt.
Gut, ich würde mal sagen, wir machen das jetzt so.
Auf den nächsten Folien sieht man noch, welche Pfade jetzt hier
einzeln durchlaufen werden.
Kann man sich auch zur Not noch zu Hause angucken.
Ist eh nur das Gleiche, wie gerade eben, nochmal in Grafisch.
Letzte Frage war noch, wie das müsste man denn machen, um die
Zweigüberdeckung noch hinzubekommen?
Und da ist die Antwort, jetzt brauchen wir halt noch hier Matrix
gleich Null.
Oder, wenn wir das vorher in der Anweisungsüberdeckung hatten mit der
Matrix Null, brauchen wir jetzt halt noch die andere Matrix dazu.
Und dann haben wir halt noch den Pfad 1, 3, Stopp auch noch dabei.
Und damit sehen wir jetzt gerade eben, also hier da oben, dieser
Zweig, der fehlt uns.
Und jetzt haben wir dann halt noch den abgearbeitet mit diesem Pfad.
So, dann Bonusaufgabe.
Ich hoffe, die hat jeder gemacht, weil die war tatsächlich geschenkt.
Warum geht Pfadeüberdeckung nicht?
Martin, sagst du uns, warum geht Pfadeüberdeckung nicht?
Machst du nicht?
Okay, also was bedeutet Pfadeüberdeckung?
Wir müssen alle möglichen Pfade durchlaufen.
Und Pfade heißt jetzt nicht, wir müssen alle Zweige mal in Kombination
abgelaufen haben, sondern wir müssen alle Zweige in Kombination zum
Beispiel bei Schleifen auch mit allen möglichen Schleifendurchläufen
angeschaut haben.
Das heißt also, wenn so eine Schleife von der Eingabe abhängt, hier
von der Matrixgröße, kann man das quasi vergessen.
Also es ist, als wenn man sagen würde, okay, wir haben irgendwie eine
Speicherbeschränkung und die Matrizen können nicht unendlich groß
werden.
Selbst dann ist es noch unpraktikabel.
Dann hätten sie da irgendwie zwei Milliarden Pfade.
Ja, ist nicht möglich.
Okay, gut.
Dann würden wir sagen, bevor wir zur Code-Inspektion kommen, machen
wir mal die E-Wahl, weil die ist spannender als die Code-Inspektion.
Und Code-Inspektion könnte man sich theoretisch auch einfach auf den
Folien anschauen.
E-Wahl ohne unsere schönen Kommentare dazu macht natürlich überhaupt
keinen Spaß.
Deshalb machen wir das jetzt mal noch schnell.
Die Zeit ist heute ganz schön knapp.
Wir haben los.
So, deshalb ohne große Umschweifung, Evaluation der Übung.
Ich hätte mit Schlimmen gerechnet, aber es war tatsächlich gar nicht
so schlimm dieses Mal.
Wir haben einen Lehrqualitätsindex von 94,4 erreicht.
Das ist tatsächlich 1,5 Prozentpunkte besser als letztes Jahr.
Wir steigern uns konsequent.
Wir schauen gleich mal noch, wie der berechnet wird.
Aber unsere Lehrequalität ist also ziemlich gut, sogar besser als in
der Vorlesung.
Ich vermute ja, das liegt hauptsächlich daran, dass hier nur die Leute
sind, die gerne in der Übung sind und deshalb uns einigermaßen gut
evaluieren.
Und die Leute, die uns gar nicht mögen, die kommen vielleicht trotzdem
noch in die Vorlesung und lassen dann halt dort ihren Frust ab.
Schade für den Chef, aber gut für uns.
Also 94,4.
Danke dafür.
Das kann man, wie gesagt, nachlesen, wie das Ding berechnet wird.
Wir schauen aber gleich auch noch mal kurz drauf.