Sollte man auf algorithmische Komplexität testen? Wenn das so ist, wie?

14

Angenommen, ich implementiere etwas Einfaches wie das Durchsuchen einer sortierten Liste / eines Arrays. Die Funktion (in c #) würde ungefähr so ​​aussehen:

static int FindIndex(int[] sortedList, int i);

Ich könnte dies in Bezug auf die Funktionalität implementieren und testen, aber aus offensichtlichen Gründen würde ich normalerweise eine binäre Suche einer linearen Suche vorziehen oder etwas absichtlich Dummes.

Meine Frage lautet also: Sollten wir versuchen, Tests zu schreiben, die die Leistung in Bezug auf die algorithmische Komplexität garantieren, und wenn ja, wie?

Ich habe angefangen, Argumente auf beiden Seiten des "sollten Sie" -Teils dieser Frage vorzubringen, aber ich würde gerne sehen, was die Leute sagen, ohne meine Argumente, um sie dazu aufzufordern.

In Bezug auf "wie" wird das sehr interessant :) Sie können sehen, wie der Vergleichsoperator parametrisiert wird und ein Test durchgeführt wird, dessen Vergleichsoperator Vergleiche oder ähnliches zählt. Aber nur weil du kannst, heißt das nicht, dass du ...

Hat jemand dies (wahrscheinlich) in Betracht gezogen? Vielen Dank.

SirPentor
quelle
@steenhulthin - Ich lasse das hier köcheln und überprüfe das. Ich war noch nie dort gewesen.
SirPentor
Übrigens, schöne Frage. +1
Rafael Colucci

Antworten:

13

Algorithmische Komplexität ist ein theoretisches Konstrukt und daher am besten mit Bleistift und Papier "getestet". Es kann nicht sinnvoll mechanisch getestet werden.

Die absolute Leistung kann mechanisch getestet werden und nützliche Komponententests durchführen. Wenn es auf die Leistung ankommt, können Sie einen Schwellenwert angeben: "Diese Abfrage sollte nicht länger als 50 ms dauern, um mit 10 6 Zahlen und nicht länger als 60 ms mit 10 7 Zahlen ausgeführt zu werden." Dafür kannst du einen Komponententest aufbauen.

Dem Endbenutzer ist es egal, ob Ihr Algorithmus linear oder logarithmisch ist. Sie kümmern sich darum, ob ihre Benutzeroberfläche immer noch sofort reagiert, selbst wenn die App Daten für ein Jahr enthält.

Crashworks
quelle
Das ist auch mein Instinkt. Aber was mich zum Nachdenken gebracht hat, ist, dass die Leistung auf Frameworks basiert. Beispiel: Wenn ich mich richtig erinnere, hat die stl einige Garantien bezüglich der algorithmischen Komplexität (könnte hier deaktiviert sein).
SirPentor
Nur weil eine Bibliothek einige Garantien bietet, bedeutet dies nicht, dass sie für Einheiten testbar sein müssen.
Svick
@Tobias Brick: Etwas testen und etwas definieren sind zwei verschiedene Dinge.
DeadMG
Leistung zu demonstrieren ist hart. Es beinhaltet viele Stichprobenpunkte für unterschiedliche Parameter. Es ist einfacher, wenn die einzelnen Funktionen trivial sind, aber darüber hinaus ... Ihre Auslastung, Ihr RAM, die Geschwindigkeit des Frontbusses, die CPU, die Anzahl der Kerne, die Aggressivität des Compilers und der Grad der Verschmutzung der Registrierung wirken sich auf die Laufzeit einer bestimmten aus Stichprobe.
Job
3

Obwohl ich nicht sicher bin, ob dieses Tool für Unit-Tests besonders nützlich sein wird, beschreibt die Arbeit "Empirical Computational Complexity" von Goldsmith, Aiken und Wilkerson eine Methode, um Code zu instrumentieren und sein dynamisches Verhalten an einer Reihe verschiedener Eingaben empirisch zu beobachten leiten ihre asymptotische Komplexität ab. Das in dem Artikel beschriebene Programm ist Open Source und steht hier zur Verfügung .

Hoffe das hilft!

templatetypedef
quelle
0

Die Hauptsache ist, es mit Big Data zu versuchen und zu sehen, ob es zu lange dauert.

In meiner Erfahrung mit der Leistungsoptimierung, wie in diesem Beispiel , passiert Folgendes: Wenn ein Algorithmus (zum Beispiel) O (n ^ 2) ist, ist dies möglicherweise in Ordnung, solange der Prozentsatz der Zeit, die dafür benötigt wird, nie auf das Radar gelangt.

Wenn jedoch ein Datensatz mit einer Größe angegeben wird, die möglicherweise nur einmal im Jahr angezeigt wird, kann der von diesem Algorithmus beanspruchte Teil der Gesamtzeit katastrophal dominant werden.

Wenn Sie dies beim Testen erreichen können, ist dies eine sehr gute Sache, da es äußerst einfach ist, das Problem zu finden, als wäre es eine tatsächliche Endlosschleife.

Mike Dunlavey
quelle
0

Ich glaube nicht, dass Sie Unit Testing machen wollen.

AFAIK, Unit-Tests sollen nur sicherstellen, dass der Code das tut, was er tun soll, und sich nicht auf die Leistung konzentrieren.

Aus Wikipedia : Es ist nicht zu erwarten, dass das Testen jeden Fehler im Programm auffängt: Es ist unmöglich, jeden Ausführungspfad in allen außer den trivialsten Programmen zu bewerten. Gleiches gilt für Unit-Tests. Darüber hinaus testet der Einheitentest per Definition nur die Funktionalität der Einheiten selbst. Daher werden Integrationsfehler oder Fehler auf Systemebene (wie z. B. Funktionen, die über mehrere Einheiten ausgeführt werden, oder nicht funktionale Testbereiche wie z. B. Leistung) nicht abgefangen. Unit-Tests sollten in Verbindung mit anderen Software-Testaktivitäten durchgeführt werden. Wie bei allen Arten von Softwaretests können Unit-Tests nur das Vorhandensein von Fehlern anzeigen. Sie können das Fehlen von Fehlern nicht anzeigen.

Es gibt andere Arten von Werkzeugen und Mustern, um die Leistung zu messen. Eines, an das ich mich jetzt erinnern kann, ist das Abnahmetesten, das sich auf nicht-funktionale Anforderungen konzentriert.

Es gibt nur wenige andere wie Leistungstests (die Stresstests, Lasttests usw. verwenden).

Sie können auch einige Stress-Tools zusammen mit einem Build-Tool (ant, automatic build studio) als Teil Ihrer Bereitstellungsschritte verwenden (das ist, was ich tue).

Die kurze Antwort lautet also nein, Sie sollten sich darüber keine Gedanken machen, wenn Sie einen Code testen.

Rafael Colucci
quelle
0

Das Übergeben des Komparators und das Verfolgen der Häufigkeit, mit der der Komparator aufgerufen wird, funktioniert aus einfachen Gründen, z. B. um zu überprüfen, ob die Anzahl der Vergleiche bei einer Suche in einer festen Eingabe (beispielsweise new int[] { 1,2,3, ... , 1024 }) unter 10 bleibt Machen Sie Ihre Absichten klar, wie sich der Algorithmus verhalten soll.

Ich denke nicht, dass Unit-Tests der richtige Weg sind, um zu überprüfen, ob Ihr Algorithmus O (log n) ist. Das würde eine Menge zufälliger Datenerzeugung, eine gewisse Kurvenanpassung und wahrscheinlich knifflige Statistiken erfordern, um festzustellen, ob eine Reihe von Datenpunkten zur erwarteten Laufzeit passt. (Für diesen Algorithmus ist es wahrscheinlich machbar, aber wenn Sie anfangen zu sortieren, wird es schwierig, die Worst-Case-Szenarien wiederholt zu treffen.)

yatima2975
quelle