Visual Studio - Was stimmt nicht mit dem Zufallsgenerator?


21.08.2020, 04:16

ich weiß nicht was das problem ist, aber es muss irgend etwas mit der Zeit zu tun haben!

wenn ich nehmlich "Thread.sleep(500);" direkt über dem zufalls befehl verwende, neigt es stark dazu die zahlen sehr zufällig zu machen.

wenn ich die milisekunden im Thread.sleep reduziere steigt die neigung immer höher an immer die gerade benutzte zahl wieder zu verwenden!

Weiß jemand woran das liegen könnte?

3 Antworten

Vom Fragesteller als hilfreich ausgezeichnet

Das liegt daran, dass du bei jeder neuen Iteration ein neues Random-Objekt anlegst. Dieses verwendet zum Generieren eines Seeds die Zeit, die sich aufgrund der extrem geringen Abstände, in denen die Iterationen vonstatten gehen, aber nicht großartig ändert. Das heißt, es wird mit jeder Iteration derselbe Seed erzeugt.

Erstelle also nur ein Random-Objekt außerhalb der Schleife bzw. besser: Lege ein Feld an und initialisiere es / definiere es im Konstruktor.


MarcelHD40 
Fragesteller
 21.08.2020, 04:19

was und wo ist der Konstruktor

0
MarcelHD40 
Fragesteller
 21.08.2020, 04:42
@regex9

Ich habe keine ahnung was das damit zu tun haben soll.

0
regex9  21.08.2020, 04:45
@MarcelHD40

Das habe ich doch oben erklärt. Du brauchst nur ein Random-Objekt, welches folglich außerhalb der Schleife erstellt werden sollte.

0
MarcelHD40 
Fragesteller
 21.08.2020, 04:48
@regex9

Der sin ist es ja aber das es in der schleife ist damit es nicht dauernd die abfrage von loginpsw von Readline macht.

0
regex9  21.08.2020, 05:00
@MarcelHD40

Da besteht jetzt überhaupt kein Zusammenhang. 🤨

Ein Random-Objekt erstellt einen Seed (und merkt sich diesen anschließend). Auf dessen Grundlage werden Zufallszahlen ermittelt (mit jedem Next-Aufruf bekommst du eine neue Zufallszahl). So einen Seed muss dein Programm also insgesamt nur ein einziges Mal (über das Random-Objekt) generieren lassen (daher sollte es als Feld/Member Variable angelegt werden). Das eine Random-Objekt wird vom Programm immer wieder genutzt, um (via Next) immer wieder eine neue Zufallszahl zu bekommen.

Wenn du das Random-Objekt aber innerhalb der Schleife erstellst, passiert das, was dich stört und was ich oben beschrieben habe. Es werden durchgehend neue Zahlenfolgen mit den exakt gleichen Zufallszahlen erstellt. Das ist sinnlos.

0
regex9  21.08.2020, 05:04
@regex9
(...) daher sollte es als Feld/Member Variable angelegt werden (...)

Gemeint ist das Random-Objekt. Wie jetzt schon mehrmals geschrieben.

0
MarcelHD40 
Fragesteller
 21.08.2020, 05:06
@regex9

das ist doch komplett verkehrt!?

ich muss doch ständig eine neue random machen um genau deswegen eine neue zufallszahl zu bekommen weil wenn die random nur ein einziges mal ausgeführt wird wäre das doch nur eine einzige konstante zahl.

0
MarcelHD40 
Fragesteller
 21.08.2020, 05:11
@regex9

ich habe es jetzt außerhalb der schleife gemacht und direkt unter dem

 static void Main(string[] args)
{

geschrieben.

Es funktioniert jetzt auch zufällig nur habe ich keine ahnung warum es jetzt auf einmal zufällig funktioniert obwohl das ja logisch komplett umgekehrt sein müsste und man doch den random ständig neu würfeln müsste um eine neue zufällige zahl raus zu bekommen?...

das ist doch voll paradox?

0
Xearox  21.08.2020, 05:11
@MarcelHD40

Es geht doch nur um das Random Objekt. Die Zufallszahlen holst du mit zufall.next

0
MarcelHD40 
Fragesteller
 21.08.2020, 05:13
@Xearox

Und was ist dann die aufgabe von Random wenn es nicht für den zufall zuständig ist?

0
Xearox  21.08.2020, 05:15
@MarcelHD40

Es erzeugt Random Objekt. Oh man... Beschäftige dich erstmal mit den Grundlagen der OOP bevor du hier solche Fragen stellst.... Sorry, aber das ist echt einer der elementarsten Grundlagen.

0
MarcelHD40 
Fragesteller
 21.08.2020, 05:20
@Xearox

Niemand erklärt das. Jedes Tutorial hämmert das einfach nur so rein weil es nunmal so ist und man es für den Zufall braucht. nicht mehr und nicht weniger.

Zumindest wird das so aufschlussreich in den Tutorials erklärt die ich schaue.

0
Xearox  21.08.2020, 05:23
@MarcelHD40

Random ist eine Klasse, mit

Random zufall = new Random();

Erzeugst du ein neues Objekt der Klasse Random, in der eben wie Regex gesagt, ein Seed erzeugt wird.

Mit zufall.next() holst du dir dann die nächste Zufallszahl, es ist also eine Funktion in der Klasse Random.

0
regex9  21.08.2020, 05:51
@MarcelHD40

Ich habe es jetzt zweimal erklärt. Wenn das nicht genügt: Zu C# / .NET gibt es auch eine Dokumentation von Microsoft. In dieser wird das Verhalten der einzelnen Elemente ebenso beschrieben.

0

Das du das "Random zufall = new Random()" vor die Schleifen setzen musst, weißt du jetzt ja schon.

Ich versuche dir zu erklären warum das so ist.

Die Random Klasse ist nicht darauf begrenzt, dir nur eine Zufallszahl zu geben, sondern beliebig viele.

Das heißt, die Klasse Random brauchst du nur einmal definieren, und kannst daraus beliebig viele Zufallszahlen bekommen

Random zufall = new Random();
int z1 = zufall.Next(1, 200);   // erste Zufallszahl aus Random
int z2 = zufall.Next(1, 200);   // zweite Zufallszahl aus Random
....
int zx = zufall.Next(1, 200);   // x-te Zufallszahl aus Random

Eine Eigenschaft der Random Klasse ist es, dass sie deterministisch ist. Das heißt, dass du bei gleichem Startwert (seed), auch die gleiche Zufallszahlenreihe raus bekommst.

Diesen Startwert, kannst du selbst bestimmen. Falls du ihn nicht selbst bestimmst, wird indirekt für dich ein Startwert definiert. Bei der Random Klasse in C# ist dieser Startwert die aktuelle Uhrzeit, auf die Sekunde genau.

Random zufall1 = new Random();   // Indirekter Startwert = aktuelle Zeit in Sekunden
Random zufall2 = new Random(4711); // Direkter Startwert = 4711

Wichtig zu verstehen ist, dass du im zweiten Fall, jedesmal wenn du dein Programm startest immer dieselben Zufallszahlen rausbekommst, wenn du Next(...) ausführst.

Warum bei dir jetzt so häufig immer dieselbe Zufallszahl rauskommt hat damit zu tun, dass du durch den Indirekten Startwert (aktuelle Zeit in Sekunden) innerhalb einer Sekunde auch immer denselben Startwert definierst, und du dadurch mit Next auch immer dieselbe Nächste Zufallszahl rausbekommst. Erst wenn eine Sekunde vergangen ist, hast du auch einen neuen Startwert und bekommst damit neue Zufallszahlen raus

Hier ein Beispiel:

// aktuelle Zeit in Sekunden = 1597990411
Random zufall = new Random(1597990411);
zufall.Next(1, 200);  // erste Zufallszahl mit Startwert 1597990411
Random zufall = new Random(1597990411);
zufall.Next(1, 200);  // erste Zufallszahl mit Startwert 1597990411
// du erhälst jetzt dieselbe Zufallszahl wie beim ersten mal, da du zweimal mit dem Startwert 1597990411 die erste Zufallszahl ermittelt hast

// eine Sekunde ist vergangen, aktuelle Zeit ist jetzt 1597990412
Random zufall = new Random(1597990412);
zufall.Next(1, 200);  // erste Zufallszahl mit Startwert 1597990412
// jetzt bekommst du, da du einen neuen Startwert hast, auch eine neue Zufallszahl als erste Zufallszahl

Dadurch, dass du die Random Klasse in der Schleife immer neu definierst, bekommst du mit Next() immer nur die allererste Zufallszahl mit deinem Startwert. Und solange ebene keine neue Sekunde anbricht, ist die allererste Zufallszahl immer dieselbe Zufallszahl wie die allererste Zufallszahl aus dem vorhergehenden Durchlauf.

Es ist jetzt etwas länger geworden, aber ich hoffe du verstehst jetzt etwas besser, warum du das Ergebnis bekommst, das du bekommen hast.

Woher ich das weiß:Berufserfahrung

Das Random Objekt ist der Würfel. Das Holen der Zufallszahl mit zufall.next() ist das Würfeln.

Ein Würfel wird mit Hilfe der aktuellen Zeit angefertigt. In der Schleife hast du hunderte gleicher Würfel, die alle die erste gleiche Zahl erzeugen. Die sind deshalb gleich, weil sie zur gleichen Zeit erzeugt wurden.

Ein einziger Würfel, mit dem man hunderte Male würfelt, macht das, was du haben willst.

Verstanden?