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?