Wiki: Mathe und Info

Unterrichtsmaterialien für Mathematik und Informatik

Benutzer-Werkzeuge

Webseiten-Werkzeuge


info:sek-ii:q3:komplexitaet:l4-laufzeitverhalten

Laufzeitmessung

Vorüberlegungen

Laufzeitmessung mit Java

Laufzeitmessungen mit Java sind ganz einfach:

long start = System.nanoTime();
tueEtwasDasLangeDauert();
double runTimeInMilliSeconds = (System.nanoTime() - start) / 1000000d;
 
println("Das hat " + runTimeInMilliSeconds + "ms gedauert!);

Hier muss nur noch statt tueEtwasDasLangeDauert(); das Programm eingefügt werden, dessen Laufzeit ermittelt werden soll.

Wenn man beispielsweise die Laufzeit einer Implementierung von SelectionSort ermitteln möchte, dann lässt sich mit dem oben beschriebenen Anweisungsmuster so realisieren:

int[] sortiere(int[] liste) {
  for (int bereichsGrenze = 0; bereichsGrenze < liste.length; bereichsGrenze++) {
    int kleinstes = bereichsGrenze;
 
    for (int i = bereichsGrenze; i < liste.length; i++) {
      if (liste[i] < liste[kleinstes]) {
        kleinstes = i;
      }
    }
 
    int tmp = liste[bereichsGrenze];
    liste[bereichsGrenze] = liste[kleinstes];
    liste[kleinstes] = tmp;
  }
 
  return liste;
}
 
void printArray2(int[] array) {
  for (int i = 0; i < array.length; i++) {
    print(array[i]);
 
    if (i < array.length - 1) {
      print(", ");
    }
  }
 
  println();
}
 
void setup() {
  int[] liste = { 25,  17,  32,  56,  25,  19,   8,  66,  29,   6,  20,  29 };
 
  print("unsortiert: ");
  printArray2(liste);
 
  print("sortieren: ");
  long start = System.nanoTime();
  liste = sortiere(liste);
  double runTime = (System.nanoTime() - start) / 1000000d;
 
  println(runTime + "ms");
 
  print("sortiert: ");
  printArray2(liste);
}
Aufgabe 1

Verwende eine Implementierung des Selection-Sort und das oben gezeigte Anweisungsmuster für verschiedene Laufzeitmessungen (denke dir eigene, unsortierte Arrays aus).

Lege eine Tabelle an:

Länge des Arrays Durchschnittliche Laufzeit
100 0.012123ms
Probleme der Laufzeitmessung

Wie stabil sind die Ergebnisse von Laufzeitmessungen, wenn man ein und dieselbe Liste mehrfach mit demselben Programm sortiert? Wir probieren das mit dem folgenden Testprogramm aus.

int[] array = new int[1000];
 
for (int j = 0; j < array.length; j++) {
  array[j] = (int)random(0, array.length);
}
 
for (int i = 0; i < 1000; i++) {
  long start = System.nanoTime();
  sortiere(array.clone());
  double runTime = (System.nanoTime() - start) / 1000000d;  
  println("Laufzeit: " + runTime + "ms");
}  

Wir könnten folgende Ausgabe erhalten:

laufzeit: 0.184849ms
laufzeit: 0.184839ms
laufzeit: 0.190099ms
laufzeit: 0.1848ms
laufzeit: 0.18484ms
laufzeit: 0.184819ms
...
Aufgabe 2
  1. Die Messergebnisse schwanken etwas. Was könnte die Ursache hierfür sein?
  2. Teste, ob du dieselben Zahlenwerte erhältst. Warum kann es sein, dass deine Messwerte in einem anderen Zahlenbereich liegen?
  3. Die folgenden Messwerte wurden bestimmt, während ein weiterer Prozess auf dem Rechner gestartet wurde. Woran erkennt man das? Auf welche Problematik deutet das hin?
Laufzeit: 1.882562ms
Laufzeit: 1.882464ms
Laufzeit: 1.882362ms
Laufzeit: 1.882561ms
Laufzeit: 1.882258ms
Laufzeit: 1.882162ms
...

Systematische Laufzeitmessung

Laufzeitmessung

Ziel der folgenden Untersuchungen ist es, das Laufzeitverhalten von Sortieralgorithmen systematisch zu ermitteln und die Ergebnisse genauer zu analysieren.

Hierzu bestimmen wir die Laufzeit $t(n)$ in Abhängigkeit der Listenlänge $n$ für wachsende Listenlängen (z.B. $n = 1000, 2000, ...$).

Die zu sortierenden Listen werden mit Zufallszahlen gefüllt. Bei der Erzeugung der Testlisten wird der Zahlenbereich, aus dem die Zufallszahlen stammen, an die Listengröße angepasst, um ähnliche Ausgangssituationen zu erhalten.

Das folgende Programm kann auf diese Weise systematisch die Laufzeiten für bestimmte Listenlängen ermitteln:

for (int anzahl = 1000; anzahl <= 10000; anzahl += 100) {
  int[] array = new int[anzahl];
 
  for (int i = 0; i < array.length; i++) {
    array[i] = (int)random(0, array.length);
  }    
 
  long start = System.nanoTime();
  sortiere(array);
  double runTime = (System.nanoTime() - start) / 1000000d;  
  println("Laufzeit bei " + anzahl + " Einträgen: " + runTime + "ms");
}
Aufgabe 1 - Selection-Sort

Du wirst Ergebnisse erhalten, die vom Prinzip her so aussehen:

Laufzeit bei 100 Einträgen: 0.072728ms
Laufzeit bei 200 Einträgen: 0.266294ms
...
Laufzeit bei 1000 Einträgen: 1.35829ms
...
Laufzeit bei 5000 Einträgen: 5.367423ms
...
Laufzeit bei 9700 Einträgen: 19.689995ms
Laufzeit bei 9800 Einträgen: 20.085863ms
Laufzeit bei 9900 Einträgen: 20.49522ms
Laufzeit bei 10000 Einträgen: 20.895475ms

Kannst du eine Vorhersage treffen, wie lange es dauert, wenn man die Rechenzeit analog für $100.000$ Listenelemente bestimmt? Versuche hierzu, anhand der Messwerte Gesetzmäßigkeiten aufzudecken: Wie ändert sich $t(n)$, wenn man $n$ verdoppelt? Überprüfe deine Vorhersage durch geeignete Tests.

Aufgabe 2 - Verschiedene Algorithmen

Neben dem Selection-Sort existieren verschiedene weitere Sortieralgorithmen. Mit diesem Tool kannst du beobachten, wie sich die Laufzeiten verschiedener Algorithmen für verschiedene Ausgangssituationen unterscheiden.

Zusammenfassung

Laufzeitanalyse mit Laufzeitmessung

Laufzeitmessungen werden in der Praxis durchgeführt, um das Laufzeitverhalten eines Programms unter Realbedingungen zu ermitteln.

Aus systematisch durchgeführten Laufzeitmessungen kann man oft Gesetzmäßigkeiten erschließen, wie die Laufzeit von den zu verarbeitenden Daten abhängt.

Bei Laufzeitmessungen muss man aber sehr genau darauf achten, dass sie unter gleichen Bedingungen erfolgen. Ein Wechsel des Rechners führt in der Regel zu anderen Ergebnissen. Auch Änderungen in der Implementierung wirken sich in der Regel auf die Messergebnisse aus. Selbst bei ein und demselben Rechner und derselben Implementierung können sich die Bedingungen ändern, da oft mehrere Prozesse gleichzeitig ablaufen.

Ergebnisse von Laufzeitmessungen sind also kaum auf andere Systeme (andere Rechner, andere Programmiersprachen) übertragbar. Um diese Schwierigkeit zu überwinden, soll im nächsten Abschnitten ein anderer Weg zur Beschreibung der Berechnungskomplexität beschritten werden.

info/sek-ii/q3/komplexitaet/l4-laufzeitverhalten.txt · Zuletzt geändert: 2022-12-12 13:52 von christian.weber