C# Zufallswerte in Instanz funktionieren nicht

Mr Speicher

Neu angemeldet
Registriert
22 Dez. 2013
Beiträge
83
Hallo, ich habe ein kleines Programm geschrieben mit dem per Zufall der Geburtstag erstellt wird sprich Tag, Monat, Jahr. Diese Methode befindet sich in einer eigenen Klasse und ich greife in Program über eine Instanz auf die Methode zu.
Mit einer While-Schleife lässt sich festlegen wie viele Zufallswerte generiert und ausgegeben werden sollen.
Das Problem ist aber, dass die Zufallswerte über die Instanz nicht richtig funktionieren, es kommen fast immer die selben Werte dabei heraus.

Hier ein Beispiel bei 20 Zufallsdurchgängen:
durchgänge.PNG

Müsste für jeden Durchgang nun eine neue Instanz erstellt werden damit es mit den Zufallszahlen klappt oder liegt der Fehler noch woanders ?

Hier ist mal der Code:
Program.cs
[src=csharp]namespace Test_2
{
class Program
{
static void Main(string[] args)
{
int anzahlDurchGaenge, hochZaehlen=0;

Console.Write("Anzahl Durchgänge eingeben: ");
anzahlDurchGaenge = Convert.ToInt32(Console.ReadLine());

Class1 aufruf = new Class1();

while (anzahlDurchGaenge >=hochZaehlen)
{
aufruf.zufallsWertGeburtstag();

hochZaehlen++;
}

Console.ReadLine();
}
}
}[/src]

Class1.cs
[src=csharp]namespace Test_2
{
class Class1
{
int tag, monat, jahr, personenAlter;

public void zufallsWertGeburtstag()
{

Random roundGB = new Random();

const int MONATALTERSBBERECHNUNG = 8, JAHRALTERSBERECHNUNG = 2015;

// Berechnungsteil für Monat, Tag und Jahr des Geburtstages
monat = roundGB.Next(1, 13);
if (monat == 2)
{
tag = roundGB.Next(1, 29);
}
else
{
tag = roundGB.Next(1, 31);
}

// Jahr berechnet mit Zufallswerten zw. 1950 und 1996
jahr = roundGB.Next(1950, 1997);

// Berechnet das Alter der Person
if (monat > MONATALTERSBBERECHNUNG)
{
personenAlter = JAHRALTERSBERECHNUNG - (jahr - 1);
}
else
{
personenAlter = JAHRALTERSBERECHNUNG - jahr;
}

Console.WriteLine(tag + "." + monat + "." + jahr + " " + personenAlter + " Jahre" + "\n");
}
}
}[/src]
 
statt random, was mit dem gleichen parameter, also in dem Fall keinem, immer die gleiche Abfolge liefert :

[src=csharp]public static int GenerateRandomNumber(int min, int max)
{
var c = new RNGCryptoServiceProvider();
// Ein integer benötigt 4 Byte
var randomNumber = new byte[4];
// Auffüllen mit einer kryptographisch starken Folge an zufälligen Werten
c.GetBytes(randomNumber);
// Umwandlung Byte-Array in Integer
int result = Math.Abs(BitConverter.ToInt32(randomNumber, 0));
// Setzen der inklusiven Grenzen
return result%max + min;
}[/src]
 
Um KaPiTN's Lösung mal zu erklären: Zufallszahlen sind am PC auch nicht wirklich zufällig, das geht nicht. Deshalb nimmt man einen bestimmten Seed, aus dem dann mittels mathematischen Verfahren Zahlen gewonnen werden, die zufällig erscheinen. Der Seed ist in den meisten Fällen zeitabhängig, weshalb hier KaPiTN nicht ganz Recht hat ( , Zeile 53). Da deine Instanzen im gleichen Tick erstellt werden, haben sie den gleichen Seed und geben die gleichen Werte. Die im obigen Beispiel genutzte Klasse umgeht das Problem, da sie die Zufallswerte nicht zeitabhängig generiert.
 
  • Thread Starter Thread Starter
  • #4
Ok, Danke für eure Ausführungen, wieder etwas gelernt.
Ich hatte gehofft es ginge so einfach über Random, jetzt werde ich mal die Lösung von KaPiTN zu implementieren.
 
Ist halt ein relativ unglücklicher Fehler. Du könntest aber einfach den Thread schlafen lassen, da die Random-Klasse den Environment-Tick-Count als Seed verwendet sollte das dir dann zufälliger wirkende Zahlen liefern.



Ich schätze, 20 Millisekunden könnten reichen (die Auflösung des Zeitgebers scheint für gewöhnlich von 10 bis 16 Millisekunden zu variieren ( )). Einfach an den Anfang oder das Ende deiner Zufallsmethode packen und mal testen.

Die tatsächliche Lösung für dein Problem ist aber ganz anders: Erstell nicht immer ein neues Random-Objekt. Das ist sehr unsauber. Du kannst es entweder als statisches Klassenattribut deklarieren, oder (was vermutlich die sinnvollste Lösung ist) von der separaten Klasse wegkommen und stattdessen das Random-Objekt als Attribut der Main-Klasse deklarieren. Dann kannst du auch die Funktion in die Main-Klasse packen.

Bei weiteren Fragen einfach Fragen :T
 
Zurück
Oben