10

I know there are multiple times this question has been put forth but none of those solutions worked for me.

First I did this in my method called RandomNumGenerator(items)

List<int> randNum = new List<int>();
foreach (var item in items)
{
    randNum.Add(new Random(1000).Next());
}

This always gave me the same number, and then after looking at this answer I did this:

Random rnd = new Random(1000);
foreach (var item in items)
{
    randNum.Add(rnd.Next());
}

This gave me the numbers as below

325467165 
506683626   
1623525913  
2344573     
1485571032

Now while that is fine for every iteration of the loop, the problem here is, when I stop and re-run the application, I get the same numbers I got earlier all over again.

325467165 
506683626   
1623525913  
2344573     
1485571032

Is this behavior during debugging only or will I have the same issue every time I call the RandomNumGenerator?

Community
  • 1
  • 1
user20358
  • 14,182
  • 36
  • 114
  • 186
  • 1
    I suggest you to declare `rnd` as `static readonly` inside the class and resuse the same instance. – Alessandro D'Andria Mar 28 '14 at 12:17
  • 1
    Lots of good answers here making it hard to choose the answer to mark correct. I am divided between the answer given by Neel and Tim Schmelter. While Tim's answer did solve my problem, Neels answer has provided me a solution to a possible future problem. – user20358 Mar 28 '14 at 12:30
  • 16
    You are seeding the generator with the same number. Omit that parameter and it will derive a seed from the clock. – Jodrell Mar 28 '14 at 16:22
  • 1
    It isn't relevant to the question right now but please use code that actually compiles for future purposes. For all we know, the problem could've been anything if you don't show us the code that gave you the results. – Jeroen Vannevel Mar 28 '14 at 20:01
  • Aside from that: you're creating a new `Random` object in every iteration of your loop. This should cause every generated value to be identical. – Jeroen Vannevel Mar 28 '14 at 20:07
  • 1
    This question has been asked and answered many times before. I see nothing distinct about this instance other than the OPs apparent confusion. – RBarryYoung Mar 30 '14 at 17:42
  • @AlessandroD'Andria Random instance is not thread safe, if you use it as a static, make sure you lock it well https://stackoverflow.com/questions/3754170/random-number-generator-returning-zeros – MichaelD Aug 22 '18 at 10:40

6 Answers6

156

You are seeding the Random instance always with the same seed 1000 here:

Random rnd = new Random(1000);

this will not do that since the current time is used as seed:

Random rnd = new Random();

Have a look at the constructor which takes an int.

Providing an identical seed value to different Random objects causes each instance to produce identical sequences of random numbers.

Tim Schmelter
  • 450,073
  • 74
  • 686
  • 939
43

As per MSDN.

public Random(
    int Seed
)

Seed

A number used to calculate a starting value for the pseudo-random number sequence. If a negative number is specified, the absolute value of the number is used.

The reason for most beginner's mistakes involving RNGs (random number generators), is the lack of understanding about what the "seed" is and what it does.


So what is a "seed"?

The Random class is a class for generating pseudo-random numbers - or numbers that appear to be random. They are usually a mathematical function, that uses a parameter - the "seed" - to generate a sequence of numbers that appear to be random.

In the case of new Random(1000), the first 5 nonnegative random integers are

325467165
506683626
1623525913
2344573
1485571032

In your first code, you create a new sequence of pseudo-random numbers with the same seed every time you need a random number, so obviously your array is filled with the same number: 325467165, which happens to be the first nonnegative integer generated by new Random(1000).

This also explains why your second code always generates the same sequence of pseudo-random numbers every time your application is launched.

To ensure your app always generate different pseudo-random sequences, you need to use a different seed each time. By far the easiest way to ensure that, is to take your time, literally.

Random rnd = new Random(DateTime.UtcNow.Millisecond);
// Taking the millisecond component, because it changes quickly

Luckily, you don't have to type this much, because the default constructor for the Random class already does something similar to that.

Random rnd = new Random(); // Much simpler, isn't it?

Keep in mind that the Random class is not thread safe; if multiple threads attempt to access the same Random object concurrently, your RNG will return only 0 for the remaining of its lifetime.

Another thing to note, is that creating multiple Random objects one after the other - even when using time as the seed - can lead to the same sequence of pseudo-random numbers.

Random r1 = new Random();
Random r2 = new Random();
Random r3 = new Random();
Random r4 = new Random();

In the above code, chances are very high, that r1, r2, r3 and r4 will all generate the same sequence.

How is that possible?
Well, (un)fortunately, CPUs are blazing fast. A 1 GHz CPU can execute about 1 billion instructions per second (give or take); that's 1 instruction every 1 nanosecond - or 1 instruction every 1 millionth of a millisecond.
Creating a new Random object might require quite a lot of instructions, but most definitely less than a million of them.


So why do we need to manually define a seed, if using the clock's current millisecond count is what we "all" want and is already the default?

Because it can be very useful for keeping multiple terminals in sync.

Imagine a game, where important phenomena randomly appear, such as a change in weather that could completely overturn the game. You wouldn't want only one side to suffer from fog, while the rest still profits from clear weather, right?

Of course, you could have the server or the host generate random weather changes and notify the players about it; or you could define a seed before the game starts, and use that seed to ensure the same "randomness" across all players throughout the game.

Isn't coding fun?

Nolonar
  • 5,962
  • 3
  • 36
  • 55
  • Supporting custom seeds but not documenting the algorithm used to generate the output is a silly combination. Will cause lots of pain when the algorithm changes between versions or different implementations of the same API. – CodesInChaos Mar 30 '14 at 08:34
19

You need to change this:

Random rnd = new Random(1000);

to

Random rnd = new Random();

From the Random Constructor docs:

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 single Random 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 the Random(Int32) constructor. For more information, see the Random(Int32) constructor.

AakashM
  • 62,551
  • 17
  • 151
  • 186
Rahul Tripathi
  • 168,305
  • 31
  • 280
  • 331
5

Key concept is random seed - the initial piece of data from which the Random derives everything else. If the seed is the same then "random" sequence will be the same.

By default the seed is set to zero, which obviously leads to repeating sequences amongst program runs.

To avoid that, you can construct your Random like this:

Random rnd = new Random();

... which is, under the hood, is:

Random rnd = new Random(Environment.TickCount);

This will init the Random object with amount of milliseconds from the OS start. This will be different each time your program starts, so you'll get different random sequences each time.

Kirill Gamazkov
  • 3,277
  • 1
  • 18
  • 22
2

Random .Next() method generates pseudo-random number. You should Declare and initialize a random object instead of creating each time new object. And no need to use any Cryctography .. :)

prvit
  • 956
  • 3
  • 9
  • 22
-1

You should use class level random variable. If you used a new Random at the method level as a local , the time-dependent seed would repeat itself generating identical sequence of random numbers.

class Program
{
 static Random _r = new Random();
 static void Main()
 {
// use _r variable to generate random number
 }
}
Mudassir Hasan
  • 28,083
  • 20
  • 99
  • 133