Analyse von Pseudozufallszahlen

Die Lösung steht am Ende des Beitrags!

 

Jeder Programmierer, der in seinem Projekt Zufallszahlen braucht, steht vor einem Problem. Gängige APIs verwenden einen, zugegeben komplexen, Algorithmus um diese zu berechnen. Als Basis dient hier z.Bsp. bei .NET (Test hier mit C-Sharp) der Zeitstempel. Weshalb auch zwei zum selben Zeitpunkt ausgeführte Zufallszahlenfunktionen stets den gleichen Wert zurückliefern.

Auf dem Weg zu einer pragmatischen Lösung dieses Dilemmas, bleibt eigentlich nur der Aufruf der Funktion zu unterschiedlichen Zeitpunkten. So weit, so gut.
Könnte man meinen…

Auf der Suche nach einer Überprüfungmöglichkeit, hatte ich folgende Idee:

Die menschliche Intelligenz glänzt vor Allem durch ihre Mustererkennung. Was lag also näher, als das Ganze auf eine visuelle Ebene zu transportieren. So habe ich aus Quadraten der Größe 9 x 9 Pixel ein Bild zeichnen lassen und die Berechnung der jeweiligen Farbe der Quadrate dem Pseudozufall überlassen. Der Codeabschnitt sieht folgendermaßen aus:

Erklärung:
z und i dienen der Positionierung. Jeder Pixel hat jeweils einen R,G und B Wert für die Farbe. Ablauf:

  • Zufallszahl für R
  • 10 ms warten
  • Zufallszahl für G
  • 20 ms warten
  • Zufallszahl für B
  • Quadrat zeichnen

Wenn ich nun das menschliche Auge bemühe, erkenne ich (und hier meine ich ganz subjektiv ICH) für die ersten ca. 14 Zeilen kein wirkliches Muster (geht es euch anders?).
Das sind 100 * 14 = 1400 Quadrate.

Dann fängt aber, wie von Geisterhand, der Algorithmus an Werte auszugeben, die wieder ein erkennbares Muster zeigen. Hier mal das Bild dazu:

Dieses Phänomen kann ich immer erkennen, auch wenn ich die Wartezeiten zwischen den rnd.Next()-Funktionen ändere.

Habe ich hier einen Denkfehler oder liegt es an der rnd.Next()-Funktion, bzw. der Random-Klasse von .NET? Ist das vielleicht .NET spezifisch?

Ich werde das Ganze jetzt mal in Java wiederholen und die Ergebnisse in den nächsten Tagen posten.

 

Update (28.03.2017):

Mit einiger Verzögerung habe ich das Ganze jetzt mal mit Java getestet und siehe da, selbst ohne Delay (Timer.sleep(ms)) liefert das Programm ein, zumindest für mich, befriedigendes Zufallsbild.

Ich kann hier beim besten Willen kein Muster mehr erkennen. Sollte demnach Java das Mittel der Wahl sein, für eine pragmatische Lösung des Problems großer Mengen an Pseudozufallszahlen mit akzeptabler Qualität?

Interessant wäre, welche Lösung Microsoft© hier vorschlägt. Ich werde das Problem mal weiterleiten.

Unter folgendem Link könnt ihr die Diskussion im Microsoft-Forum verfolgen:

https://social.msdn.microsoft.com/Forums/vstudio/de-DE/7ffa7592-19eb-40e7-bfa2-c7b4e0f56004/qualitt-von-pseudozufallszahlen?forum=dotnetframeworkde

Ich freue mich über alle Kommentare zu dem Thema.

Die Lösung kommt von Tom (Koopakiller) aus dem MSDN-Forum:

Ein wirkliches Problem ist jedoch das mehrfache erzeugen der Random-Klasse. Denn bei jedem startet der Algorithmus neu und die Startwerte verändern sich öfter (fast) gar nicht, weil Environment.TickCount gecached wird.

Computer nutzen nach außen hin immer so extrem exakte Werte. In Wahrheit wird da aber meistens sehr viel gecached und gerundet, was auch keine Probleme macht. Daher gibt es wirklich häufig den exakt selben Startwert.

 

Also den Konstruktor für die Random-Variable vor die Schleife gesetzt und die Ergebnisse sind wie erwartet:

 

 

Hinweis:
Die Diskussionen in diesem Blog, insbesondere Codebeispiele, gehen nicht in Produkte von logicum software ein. Dieser Blog ist vollständig frei von kommerzieller Nutzung.