How do I make my C# random number generator change with each time the constructor is called?
Solution 1
If you initialize several Random
instances using the default constructor, Random()
, within a short time period, then you risk that they would end up with the same seed value (which is time-dependant) and, therefore, generate the same random sequence each time.
You can fix this issue by initializing a single static Random
instance, and share it among all Student
instances. This is perfectly safe as long as you’re not multi-threading.
public class Student
{
private static readonly Random random = new Random();
}
From the MSDN page on the Random() constructor:
The default seed value is derived from the system clock and has finite resolution. As a result, different
Random
objects that are created in close succession by a call to the default constructor will have identical default seed values and, therefore, will produce identical sets of random numbers. This problem can be avoided by using a singleRandom
object to generate all random numbers. You can also work around it by modifying the seed value returned by the system clock and then explicitly providing this new seed value to theRandom(Int32)
constructor. For more information, see theRandom(Int32)
constructor.
Edit: Although you state that your random number generator is already a static member, this is still not enough if you’re instantiating it repeatedly (redundantly) during each Student
initialization. The following code is still incorrect:
public class Student
{
private static Random random;
private int[] numbers;
public Student()
{
random = new Random();
numbers = new int[10];
for (int i = 0; i < 10; ++i)
numbers[i] = random.Next();
}
}
You need to replace it with a version that only instantiates Random
once, like so:
public class Student
{
private static readonly Random random = new Random();
private int[] numbers;
public Student()
{
numbers = new int[10];
for (int i = 0; i < 10; ++i)
numbers[i] = random.Next();
}
}
Solution 2
A common pitfall with Random
is to create a new instance each time you need a random value.
for (int i = 0; i < 1000; i++) {
var random = new Random();
list.Add(random.Next());
}
This does not work as expected, since Random
uses the actual time to create the first random value. However, the time clock has a limited resolution. It can be that several succeeding iterations return the same time and thus the same (pseudo) random value!
The solution is to create random
only once.
var random = new Random();
for (int i = 0; i < 1000; i++) {
list.Add(random.Next());
}
You could also declare random
as a static class member
public static readonly Random RandomGenerator = new Random();
Solution 3
A random number generator uses the system time as a seed. I wonder if you are possibly declaring a new generator and calling it before the system has time to move on to its next increment. The processor cycles are actually more than often faster than the system clock. Can you post a code example?
I would suggest declaring a Static generator as either a class property or somewhere else accessible, instantiate it as final. This will guarantee that you wont be overwriting the generator with another.
ivarlee
Updated on June 04, 2022Comments
-
ivarlee about 2 years
I have two classes, a Teacher class and a Student class. In my program I create an array of 10 Teacher objects and within each Teacher object is an array of 10 Student Objects. Each Student object also has an array of integers as a member variabe, and when each Student is instantiated, it's own array of integers are filled with numbers from a random number generator. My program goes something like this:
- An array of type Teacher is created with size 10
- The array is then filled with 10 actual teacher objects
- Each Teacher object contains an array of Student objects of size 10 as a member variable
- The Student array in each Teacher object is filled with actual Student objects
- Each student object has an array of integers that are filled with random numbers in the Student objects constructor.
Here is the problem I ran into: It seems that every time the 10 Student objects are created for each Teacher, the random number generator within the Student object constructor does not reset or change even when I call the .Next() function until the next set of 10 Student objects are created for the next Teacher object. What I want is the 10 Teacher objects to each have their own Student Objects which have their own integer arrays filled with randomly generated numbers.
Any help would be appreciated! I ran into this sort of problem with constructors with my last question, and that was a matter of whether something was to be static or not and I'm not sure that's the case this time. Please ask me questions if I wasn't clear enough about anything!!
UPDATE** So after looking at MSDN, I found in their sample code "Thread.Sleep(2000)" and stuck it into my Student Constructor just to see what it did. It seemed to have solved the problem although my program runs a lot slower now, is there a minimum sleep value to wait until the Random.Next() uses a new seed from the clock and even if I did solve the problem, is there a better way to do this? My random number generator is already a static member variable of Student.