How to Seed a Random Class to Avoid Getting Duplicate Random Values

How do I seed a random class to avoid getting duplicate random values

You should not create a new Random instance in a loop. Try something like:

var rnd = new Random();
for(int i = 0; i < 100; ++i)
Console.WriteLine(rnd.Next(1, 100));

The sequence of random numbers generated by a single Random instance is supposed to be uniformly distributed. By creating a new Random instance for every random number in quick successions, you are likely to seed them with identical values and have them generate identical random numbers. Of course, in this case, the generated sequence will be far from uniform distribution.

For the sake of completeness, if you really need to reseed a Random, you'll create a new instance of Random with the new seed:

rnd = new Random(newSeed);

How to randomize seed in C#

Create your Randomobject outside the loop and don't provide the seed parameter -- one will be picked for you. By taking it out of the loop, rnd.Next() will give you a random sequence anyway.

   var rnd = new Random();     
for( int i=0; i<5; i++) {
int max_val = 10; // max value
int randind = rnd.Next(0, max_val);
Console.WriteLine(randind);
}

How to avoid duplicate System.Random inside foreach loops?

You should keep a single instance of Random, instead of reinitializing it everytime

System.Random rand = new System.Random();

foreach (var entry in somelist)
{
int random_number = rand.Next(2, 13);
echo($"{random_number}");
}

Random is initialized using identical seed values based on System Clock and therefore, if you were to reinitialize it in quick succession (as in the loop in the sample code given in OP), there is every chance you might end up with duplicates.

For example,

Random rand1 = new Random();
Random rand2 = new Random();
Thread.Sleep(2000);
Random rand3 = new Random();

Console.WriteLine(rand1.Next());
Console.WriteLine(rand2.Next());
Console.WriteLine(rand3.Next());

In the above code, it is most likely that rand1 and rand2 produces identical numbers. However, rand3 could be different as it is initialized after 2 seconds.

In fact, rand1 and rand2 is most likely to produce same series if you were to generate n random numbers.

  var r1 = Enumerable.Range(1,10).Select(x=>rand1.Next());
var r2 = Enumerable.Range(1,10).Select(x=>rand2.Next());

Creating random numbers with no duplicates

The simplest way would be to create a list of the possible numbers (1..20 or whatever) and then shuffle them with Collections.shuffle. Then just take however many elements you want. This is great if your range is equal to the number of elements you need in the end (e.g. for shuffling a deck of cards).

That doesn't work so well if you want (say) 10 random elements in the range 1..10,000 - you'd end up doing a lot of work unnecessarily. At that point, it's probably better to keep a set of values you've generated so far, and just keep generating numbers in a loop until the next one isn't already present:

if (max < numbersNeeded)
{
throw new IllegalArgumentException("Can't ask for more numbers than are available");
}
Random rng = new Random(); // Ideally just create one instance globally
// Note: use LinkedHashSet to maintain insertion order
Set<Integer> generated = new LinkedHashSet<Integer>();
while (generated.size() < numbersNeeded)
{
Integer next = rng.nextInt(max) + 1;
// As we're adding to a set, this will automatically do a containment check
generated.add(next);
}

Be careful with the set choice though - I've very deliberately used LinkedHashSet as it maintains insertion order, which we care about here.

Yet another option is to always make progress, by reducing the range each time and compensating for existing values. So for example, suppose you wanted 3 values in the range 0..9. On the first iteration you'd generate any number in the range 0..9 - let's say you generate a 4.

On the second iteration you'd then generate a number in the range 0..8. If the generated number is less than 4, you'd keep it as is... otherwise you add one to it. That gets you a result range of 0..9 without 4. Suppose we get 7 that way.

On the third iteration you'd generate a number in the range 0..7. If the generated number is less than 4, you'd keep it as is. If it's 4 or 5, you'd add one. If it's 6 or 7, you'd add two. That way the result range is 0..9 without 4 or 6.

Java Random class, generate a duplicate number using the same seed and nextBytes()?

Class Random uses a linear congruence generator with a very large period. It does not repeate an int value for a very long time. The call to nextBytes with an 8-byte array generates two int values and breaks each into four 8-bit values to fill the array.

I believe it is impossible for consecutive calls to nextBytes to generate the same values. It would mean that the random number generator would have a period of 2. The docs specify a specific behavior for next that makes this impossible. (A subclass of Random, of course, can have any kind of pathological behavior you like, but an instance of java.util.Random will be well-behaved.)

Seeding Multiple Random Number Generators

1) Is it a good idea to create multiple instances of the same random number generator with different seeds and use these random number generators in different parts of the program?

No. The above scheme is in general not recommended.

In his book, The Art of Computer Programming, Volume 2: Seminumerical Algorithms. Addison-Wesley, Reading, MA, third edition, 1997, Dr. Knuth states that

It is not easy to invent a foolproof source of random numbers.

In this case, I point out that taking subsequences from a random sequence may be less random than the original sequence of random numbers:

  • Random Numbers
  • PCG

Notice that Micosoft's Random implementation is based on a subractive lagged-fibonacci generator:

  • Reference Source - System.Random

This kind of random number generator is known for an inbuilt three-point correlation, after all, we're generating the next random number:
Subtractive Lagged-Fibonacci Generator

These kinds of Random Number Generators also depend heavily on the initialisation of their initial 55 number state. Poor initialisation may lead to poor random numbers. In the above case, similar states, may result in correlated random numbers from each of the different random number generators. Microsoft even recommends against this in their MSDN post about System.Random: MSDN The System.Random class and thread safety:

Instead of instantiating individual Random objects, we recommend that you create a single Random instance to generate all the random numbers needed by your app.

We shall look at an example where a particular initialisation creates strong correlation between the different random number generators and look for alternatives.

2) I have implemented a program that attempts to initialise 64 instances of Random as described above so that we observe any visible flaws. I chose a particular initialisation as a proof of concept:

int size = 64;    // The number of random numbers generators
int length = 20; // The number of random numbers from each generator
int steps = 18; // Move 18 steps forward in the beginning to show a particular phenomenon

Random[] r = new Random[size];

for (int i = 0; i < size; i++)
{
r[i] = new Random(i + 1);

// move RNG forward 18 steps
for (int j = 0; j < steps; j++)
{
r[i].Next(3);
}
}


for (int i = 0; i < size; i++)
{
for (int j = 0; j < length; j++)
{
Console.Write(r[i].Next(3) + ", "); // Generate a random number, 0 represents a small number, 1 a medium number and 2 a large number
}

Console.WriteLine();
}

This program generates the output shown here, each row represents the output from another RNG:

Output of the program

Notice that the highlighted columns: at particular places the RNGs seem to synchronise and produce output that does not look independent from each other.

I also wish to add another note, that creating a single list of random numbers and taking one random number from the list of each row also produces poor looking random numbers (the RNG being used here is known to have fail some statistical after all!).

3) The type of RNG used depends on your context. Some may be happy with the above output. In other cases, the RNG used may be unusable (Monte Carlo Simulation and Cryptography are two scenarios where System.Random should never be used, even for one stream of random numbers).

If you need to extract multiple subsequences of Random Numbers, find an RNG that has been designed for that purpose:

  • PCG

4) Finally, what if I want to use System.Random in multiple threads?
Microsoft MSDN has the answer in the same link I referred to above:

  • MSDN The System.Random class and thread safety

C# / Random() returns same values when launched by Task Scheduler

True randomness is not really possible in computers. Instead we use pseudo-random number generators.

The rules is that given the same seed and the same sequence of orders, the pseude-RNG will always return the exactly same results.

By default Random will implicitly retreive a seed value based on the local DateTime. As that is a derviate of Unix Time (every tick since moment X), you will only get duplicates in rare cases (creating instances milliseconds appart, a common cause of issues with Random).

What you do is give it the seed value based on hour, minute and second. And 7:00:00 PM today has the same values here as 7:00:00 PM tomorrow.



Related Topics



Leave a reply



Submit