it-swarm.com.de

Wie soll ich die Zufälligkeit testen?

Betrachten Sie eine Methode zum zufälligen Mischen von Elementen in einem Array. Wie würden Sie einen einfachen, aber robusten Komponententest schreiben, um sicherzustellen, dass dies funktioniert?

Ich habe zwei Ideen entwickelt, die beide bemerkenswerte Mängel aufweisen:

  • Mische das Array und stelle dann sicher, dass seine Reihenfolge von der vorherigen abweicht. Das hört sich gut an, schlägt aber fehl, wenn das Mischen zufällig in derselben Reihenfolge gemischt wird. (Unwahrscheinlich, aber möglich.)
  • Mische das Array mit einem konstanten Startwert und vergleiche ihn mit der vorgegebenen Ausgabe. Dies beruht darauf, dass die Zufallsfunktion bei gleichem Startwert immer dieselben Werte zurückgibt. Dies ist jedoch manchmal eine ngültige Annahme .

Stellen Sie sich eine zweite Funktion vor, die Würfelwürfe simuliert und eine Zufallszahl zurückgibt. Wie würden Sie diese Funktion testen? Wie würden Sie testen, dass die Funktion ...

  • gibt Sie niemals eine Zahl außerhalb der angegebenen Grenzen zurück?
  • gibt Zahlen in einer gültigen Verteilung zurück? (Uniform für einen Würfel, normal für eine große Anzahl von Würfeln.)

Ich suche nach Antworten, die Einblicke in das Testen nicht nur dieser Beispiele, sondern auch zufälliger Codeelemente im Allgemeinen bieten. Sind Unit-Tests hier überhaupt die richtige Lösung? Wenn nicht, welche Art von Tests gibt es?


Nur um alle zu beruhigen, schreibe ich nicht meinen eigenen Zufallszahlengenerator.

135
dlras2

Ich denke nicht, dass Unit-Tests das richtige Werkzeug sind, um Zufälligkeiten zu testen. Ein Komponententest sollte eine Methode aufrufen und den zurückgegebenen Wert (oder Objektstatus) gegen einen erwarteten Wert testen. Das Problem beim Testen der Zufälligkeit besteht darin, dass für die meisten Dinge, die Sie testen möchten, kein Erwartungswert vorhanden ist. Sie können mit einem bestimmten Startwert testen, dies testet jedoch nur die Wiederholbarkeit . Es gibt Ihnen keine Möglichkeit zu messen , wie zufällig die Verteilung ist oder ob sie überhaupt zufällig ist.

Glücklicherweise gibt es viele statistische Tests, die Sie ausführen können, z. B. Diehard Battery of Tests of Randomness . Siehe auch:

  1. Wie teste ich einen Pseudozufallszahlengenerator?

    • Steve Jessop empfiehlt, dass Sie eine getestete Implementierung des gleichen RNG-Algorithmus finden, den Sie verwenden, und dessen Ausgabe mit ausgewählten Seeds mit Ihrer eigenen Implementierung vergleichen.
    • Greg Hewgill empfiehlt die ENT Suite statistischer Tests.
    • John D. Cook verweist die Leser auf seinen CodeProject-Artikel Simple Random Number Generation , der eine Implementierung des Kolmogorov-Smirnov-Tests enthält, der in Donald Knuths Band 2, Seminumerical Algorithms, erwähnt wird.
    • Mehrere Personen empfehlen, zu testen, ob die Verteilung der generierten Zahlen gleichmäßig ist, den Chi-Quadrat-Test und den Mittelwert und die Standardabweichung innerhalb des erwarteten Bereichs zu testen. (Beachten Sie, dass das Testen der Verteilung allein nicht ausreicht. [1,2,3,4,5,6,7,8] ist eine gleichmäßige Verteilung, aber sicherlich nicht zufällig.)
  2. nit Testing mit Funktionen, die zufällige Ergebnisse zurückgeben

    • Brian Genisio weist darauf hin, dass das Verspotten Ihres RNG eine Option ist, um Ihre Tests wiederholbar zu machen, und bietet C # -Beispielcode.
    • Wiederum weisen mehrere Personen darauf hin, feste Keimwerte für die Wiederholbarkeit und einfache Tests für die gleichmäßige Verteilung, das Chi-Quadrat usw. zu verwenden.
  3. nit Testing Randomness ist ein Wiki-Artikel, der über viele der Herausforderungen spricht, die bereits angesprochen wurden, als versucht wurde, das zu testen, was seiner Natur nach nicht wiederholbar ist. Ein interessantes Stück, das ich daraus gelernt habe, war das Folgende:

    Ich habe gesehen, dass Winzip zuvor als Werkzeug zum Messen der Zufälligkeit einer Wertedatei verwendet wurde (je kleiner die Datei komprimiert werden kann, desto weniger zufällig ist sie natürlich).

104
Bill the Lizard

1. Testen Sie Ihren Algorithmus

Für die erste Frage würde ich eine gefälschte Klasse erstellen, in der Sie eine Folge von Zufallszahlen eingeben, für die Sie das Ergebnis Ihres Algorithmus kennen. Auf diese Weise stellen Sie sicher, dass der von Ihnen erstellte Algorithmus oben Ihrer Zufallsfunktion funktioniert. Also etwas in der Art von:

Random r = new RandomStub([1,3,5,3,1,2]);
r.random(); //returns 1
r.random(); //returns 3
...

2. Überprüfen Sie, ob Ihre Zufallsfunktion sinnvoll ist

Zum Komponententest sollten Sie einen Test hinzufügen, der mehrmals ausgeführt wird und bestätigt, dass die Ergebnisse vorliegen

  • liegen innerhalb der von Ihnen festgelegten Grenzen (ein Würfelwurf liegt also zwischen 1 und 6) und
  • zeigen Sie eine vernünftige Verteilung (führen Sie mehrere Testläufe durch und prüfen Sie, ob die Verteilung innerhalb von x% Ihrer Erwartungen liegt, z. B. für den Würfelwurf sollte ein 2 zwischen 10% und 20% (1/6) angezeigt werden = 16,67%) der Zeit, in der Sie es 1000 Mal gewürfelt haben).

3. Integrationstest für den Algorithmus und die Zufallsfunktion

Wie oft würden Sie erwarten, dass Ihr Array in der ursprünglichen Sortierung sortiert wird? Sortieren Sie ein paar hundert Mal und behaupten Sie, dass sich die Sortierung nur x% der Zeit nicht ändert.

Dies ist eigentlich schon ein Integrationstest, Sie testen den Algorithmus zusammen mit der Zufallsfunktion. Sobald Sie die echte Zufallsfunktion verwenden, können Sie nicht mehr mit einzelnen Testläufen davonkommen.

Aus Erfahrung (ich habe einen genetischen Algorithmus geschrieben) würde ich sagen, dass die Kombination des Einheitentests Ihres Algorithmus, des Verteilungstests Ihrer Zufallsfunktion und des Integrationstests der richtige Weg ist.

21
sebastiangeiger

Ein Aspekt von PRNGs, der vergessen zu sein scheint, ist, dass alle seine Eigenschaften statistischer Natur sind: Sie können nicht erwarten, dass das Mischen eines Arrays zu einer anderen Permutation führt als die, mit der Sie begonnen haben. Wenn Sie ein normales PRNG verwenden, ist das einzige, was Sie garantiert haben, dass es (hoffentlich) kein einfaches Muster verwendet und dass es eine gleichmäßige Verteilung auf die zurückgegebenen Zahlen hat.

Bei einem ordnungsgemäßen Test für a PRNG wird es mindestens 100 Mal ausgeführt und anschließend die Verteilung der Ausgabe überprüft (dies ist eine direkte Antwort auf den zweiten Teil der Frage).

Die Antwort auf die erste Frage ist fast dieselbe: Führen Sie den Test ungefähr 100 Mal mit {1, 2, ..., n} aus und zählen Sie, wie oft sich jedes Element an jeder Position befunden hat. Sie sollten alle ungefähr gleich sein, wenn die Mischmethode gut ist.

Eine ganz andere Sache ist das Testen von PRNGs mit Kryptographie-Qualität. Dies ist eine Angelegenheit, in der Sie wahrscheinlich nicht verweilen sollten, es sei denn, Sie wissen wirklich, was Sie tun. Es ist bekannt, dass Menschen zerstören (lesen: katastrophale Löcher öffnen) gute Kryptosysteme mit nur wenigen 'Optimierungen' oder trivialen Änderungen.

EDIT: Ich habe die Frage, die Top-Antwort und meine eigene gründlich durchgelesen. Während die Punkte, die ich mache, noch bestehen, würde ich die Antwort von Bill The Lizard unterstützen. Unit-Tests sind von Natur aus boolesch - sie schlagen entweder fehl oder sie sind erfolgreich und eignen sich daher nicht zum Testen, "wie gut" die Eigenschaften von a PRNG (oder einer Methode, die ein PRNG verwendet) sind. da jede Antwort auf diese Frage eher quantitativ als polar wäre.

15
K.Steff

Lassen Sie es einige Male laufen und visualisieren Sie Ihre Daten .

Hier ist ein Beispiel für ein Shuffle von Coding Horror . Sie können sehen, dass der Algorithmus in Ordnung ist oder nicht:

enter image description here

Es ist leicht zu erkennen, dass jedes mögliche Element mindestens einmal zurückgegeben wird (die Grenzen sind in Ordnung) und dass die Verteilung in Ordnung ist.

7
Carra

Dies besteht aus zwei Teilen: Testen der Randomisierung und Testen von Dingen, die Randomisierung verwenden.

Das Testen der Randomisierung ist relativ einfach. Sie überprüfen, ob der Zeitraum des Zufallszahlengenerators so ist, wie Sie es erwarten (für einige Stichproben mit ein paar zufälligen Samen innerhalb eines bestimmten Schwellenwerts), und ob die Verteilung der Ausgabe über eine große Stichprobengröße wie erwartet ist es zu sein (innerhalb einer Schwelle).

Das Testen von Dingen, die Randomisierung verwenden, wird am besten mit einem deterministischen Pseudozufallszahlengenerator durchgeführt. Da die Ausgabe der Randomisierung basierend auf dem Startwert (seinen Eingaben) bekannt ist, können Sie den Unit-Test wie gewohnt basierend auf Eingaben und erwarteten Ausgaben durchführen. Wenn Ihr RNG nicht deterministisch ist, verspotten Sie es mit einem deterministischen (oder einfach nicht zufälligen). Testen Sie die Randomisierung isoliert von dem Code, der sie verbraucht.

6
Telastyn

Allgemeine Hinweise, die ich beim Umgang mit Code für zufällige Eingaben als nützlich empfunden habe: Überprüfen Sie die Edge-Fälle der erwarteten Zufälligkeit (Max- und Min-Werte sowie gegebenenfalls die Max + 1- und Min-1-Werte). Überprüfen Sie Stellen (an, über und unter), an denen Zahlen Wendepunkte haben (dh -1, 0, 1 oder größer als 1, kleiner als 1 und nicht negativ für Fälle, in denen ein Bruchwert die Funktion beeinträchtigen könnte). Überprüfen Sie einige Stellen vollständig außerhalb der zulässigen Eingabe. Überprüfen Sie einige typische Fälle. Sie können auch eine zufällige Eingabe hinzufügen, aber für einen Komponententest, der den unerwünschten Nebeneffekt hat, dass nicht jedes Mal, wenn der Test ausgeführt wird, derselbe Wert getestet wird (ein Seed-Ansatz kann jedoch funktionieren, testen Sie die ersten 1.000 Zufallszahlen aus dem Seed S oder so).

Zum Testen der Ausgabe einer Zufallsfunktion ist es wichtig, das Ziel zu identifizieren. Ist es bei Karten das Ziel, die Gleichmäßigkeit des 0-1-Zufallsgenerators zu testen, um festzustellen, ob alle 52 Karten im Ergebnis erscheinen, oder ein anderes Ziel (möglicherweise die gesamte Liste und mehr)?

In diesem speziellen Beispiel müssen Sie davon ausgehen, dass Ihr Zufallszahlengenerator undurchsichtig ist (genau wie es keinen Sinn macht, den Betriebssystem-Syscall oder Malloc zu testen, es sei denn, Sie schreiben Betriebssysteme). Es kann nützlich sein, den Zufallszahlengenerator zu messen, aber Ihr Ziel ist es nicht, einen Zufallsgenerator zu schreiben, nur um zu sehen, dass Sie jedes Mal 52 Karten erhalten und dass diese die Reihenfolge ändern.

Das ist eine lange Art zu sagen, dass es hier wirklich zwei Testaufgaben gibt: Testen, ob das RNG die richtige Verteilung erzeugt, und Überprüfen, ob Ihr Karten-Shuffle-Code dieses RNG verwendet, um zufällige Ergebnisse zu erzielen. Wenn Sie das RNG schreiben, verwenden Sie statistische Analysen, um Ihre Verteilung zu belegen. Wenn Sie den Kartenmischer schreiben, stellen Sie sicher, dass in jeder Ausgabe 52 nicht wiederholte Karten vorhanden sind (dies ist ein besserer Fall für einen Test durch Inspektion, den Sie verwenden das RNG).

4
anon

Sie können sich auf sichere Zufallszahlengeneratoren verlassen

Ich hatte gerade einen schrecklichen Gedanken: Sie schreiben nicht Ihren eigenen Zufallszahlengenerator, oder?

Angenommen, Sie sind es nicht, dann sollten Sie testen Sie den Code, für den Sie verantwortlich sind, nicht den Code anderer Personen (wie die Implementierung von SecureRandom für Ihr Framework).

Testen Sie Ihren Code

Um zu testen, ob Ihr Code korrekt reagiert, verwenden Sie normalerweise eine Methode mit geringer Sichtbarkeit, um die Zufallszahlen zu erstellen, damit sie von einer Komponententestklasse leicht überschrieben werden können. Diese überschriebene Methode verspottet effektiv den Zufallszahlengenerator und gibt Ihnen die vollständige Kontrolle darüber, was wann produziert wird. Folglich können Sie Ihren Code vollständig ausüben, was das Ziel von Unit-Tests ist.

Natürlich werden Sie die Kantenbedingungen überprüfen und sicherstellen, dass das Mischen genau so stattfindet, wie es Ihr Algorithmus bei den entsprechenden Eingaben vorschreibt.

Testen des sicheren Zufallszahlengenerators

Wenn Sie sich nicht sicher sind, ob der sichere Zufallszahlengenerator für Ihre Sprache nicht wirklich zufällig oder fehlerhaft ist (liefert Werte außerhalb des Bereichs usw.), müssen Sie eine detaillierte statistische Analyse der Ausgabe über mehrere hundert Millionen Iterationen durchführen. Zeichnen Sie die Häufigkeit des Auftretens jeder Zahl auf und sie sollte mit gleicher Wahrscheinlichkeit angezeigt werden. Wenn die Ergebnisse auf die eine oder andere Weise verzerrt sind, sollten Sie Ihre Ergebnisse den Framework-Designern melden. Sie werden definitiv daran interessiert sein, das Problem zu beheben, da sichere Zufallszahlengeneratoren für viele Verschlüsselungsalgorithmen von grundlegender Bedeutung sind.

4
Gary Rowe

Nun, Sie werden nie 100% sicher sein, also ist das Beste, was Sie tun können, dass es wahrscheinlich ist, dass die Zahlen zufällig sind. Wählen Sie eine Wahrscheinlichkeit aus - sagen Sie, dass eine Stichprobe von Zahlen oder Elementen bei einer Million Stichproben innerhalb einer Fehlergrenze x-mal auftaucht. Führen Sie das Ding millionenfach aus und prüfen Sie, ob es innerhalb des Spielraums liegt. Glücklicherweise machen Computer solche Dinge einfach.

1
Matthew Flynn

Um zu testen, ob eine Quelle von Zufallszahlen etwas erzeugt, das zumindest den Anschein von Zufälligkeit hat, würde ich den Test eine ziemlich große Folge von Bytes generieren lassen, sie in eine temporäre Datei schreiben und dann nach Fourmilab's) schälen ent tool. Geben Sie den Schalter -t (knapp) ein, damit eine einfach zu analysierende CSV generiert wird. Überprüfen Sie dann die verschiedenen Zahlen, um festzustellen, ob sie "gut" sind.

Um zu entscheiden, welche Zahlen gut sind, verwenden Sie eine bekannte Zufallsquelle , um Ihren Test zu kalibrieren. Der Test sollte fast immer bestehen, wenn ein guter Satz von Zufallszahlen angegeben wird. Da selbst eine wirklich zufällige Sequenz eine Wahrscheinlichkeit hat, eine Sequenz zu generieren, die nicht zufällig zu sein scheint, können Sie keinen Test erhalten, der mit Sicherheit bestanden wird. Sie wählen nur Schwellenwerte aus, die es unwahrscheinlich machen, dass eine zufällige Sequenz einen Testfehler verursacht. Macht Zufälligkeit nicht Spaß?

Hinweis: Sie können keinen Test schreiben, der zeigt, dass a PRNG eine "zufällige" Sequenz generiert. Sie können nur einen Test schreiben, der, wenn er erfolgreich ist, eine gewisse Wahrscheinlichkeit anzeigt, dass die vom = generierte Sequenz PRNG ist "zufällig". Willkommen zur Freude der Zufälligkeit!

1
Wayne Conrad

Fall 1: Testen eines Shuffle:

Betrachten Sie ein Array [0, 1, 2, 3, 4, 5], mischen Sie es, was kann schief gehen? Das übliche Zeug: a) überhaupt kein Mischen, b) Mischen von 1-5, aber nicht 0, Mischen von 0-4, aber nicht 5, Mischen und immer das gleiche Muster erzeugen, ...

Ein Test, um sie alle zu fangen:

Mische 100 Mal und addiere die Werte in jedem Slot. Die Summe jedes Steckplatzes sollte einander ähnlich sein. Avg/Stddev kann berechnet werden. (5 + 0) /2=2,5, 100 * 2,5 = 25. Der erwartete Wert liegt beispielsweise bei 25.

Wenn die Werte außerhalb des Bereichs liegen, besteht eine geringe Wahrscheinlichkeit, dass Sie ein falsches Negativ erhalten. Sie können berechnen, wie groß diese Chance ist. Wiederholen Sie den Test. Natürlich besteht eine geringe Wahrscheinlichkeit, dass der Test zweimal hintereinander fehlschlägt. Sie haben jedoch keine Routine, die Ihre Quelle automatisch löscht. Wenn der Komponententest fehlschlägt, oder? Führen Sie es erneut aus!

Es kann 3 mal hintereinander scheitern? Vielleicht sollten Sie Ihr Glück bei der Lotterie versuchen.

Fall 2: Würfeln

Die Würfelwurffrage ist dieselbe Frage. Wirf die Würfel 6000 Mal.

for (i in 0 to 6000) 
    ++slot [Random.nextInt (6)];
return (slot.max - slot.min) < threshold;
1
user unknown