146

I have the following code inside a static method in a static class:

Random r = new Random();
int randomNumber = r.Next(1,100);

I have this inside a loop and I keep getting the same randomNumber!

Any suggestions here?

AlG
  • 14,697
  • 4
  • 41
  • 54
leora
  • 188,729
  • 360
  • 878
  • 1,366
  • 4
    Why? You can pass in a seed to the constructor. Do you really need to be able to reseed it? And why can't you just create a new one with the new seed? – Matthew Scharley Nov 23 '09 at 20:38
  • I'm not complaining about the method/constructor design, but how people understand it. They only see "new Random()" and "r.Next" and think that it will choose a different seed for them, but it doesn't. – schnaader Nov 23 '09 at 20:41
  • 7
    schnaader: People don't have a problem because they cannot reseed `Random` class. Their real problem is that they are misusing it. – Mehrdad Afshari Nov 23 '09 at 20:43
  • /agree with Mehrdad. Adding a seed method, and reseeding in this example would not solve the problem. The seed is based on the timestamp, and given the fact that this code is run in a tight for loop, and the speed of modern computers, it will get reseeded at the same "time". The seeding has to be done once. – McKay Nov 23 '09 at 21:13

8 Answers8

414

A good seed generation for me is:

Random rand = new Random(Guid.NewGuid().GetHashCode());

It is very random. The seed is always different because the seed is also random generated.

joppiesaus
  • 5,471
  • 3
  • 26
  • 36
  • 26
    +1 Elegant random generator! Thanks, this is what i was googling for. – Martin Nov 19 '13 at 10:03
  • 8
    Solved my problem two application being launched at the exact same time and getting the exact same seed value. – Paul Shriner Dec 13 '13 at 22:39
  • 11
    Technically a Guid based seed will not be random, but have a degree of uniqueness. Also the uniqueness is reduced by using GetHashCode() since a Guid can take more values than an int. For many, if not most, cases though, this is good enough. – André C. Andersen Dec 15 '13 at 18:33
  • 3
    @AndréChristofferAndersen How do you know? http://dilbert.com/dyn/str_strip/000000000/00000000/0000000/000000/00000/2000/300/2318/2318.strip.gif – joppiesaus Apr 04 '14 at 15:53
  • 23
    `Guid.NewGuid()` actually has to use a random generator to create the GUID in the first place (along with other data such as time and location). Also it is slower than using `new Random()` without parameters, which sets the seed from the system time, and isn't any less random. – intrepidis Dec 24 '14 at 11:25
  • 3
    @ChrisNash System time is not random _in the context_ of a loop. Why? Because it changes _over time_, and cumputers are generally damn fast! The reason OP got the same sequence is _because_ the default constructor seeds with time, and the computer is so fast that time, measured in the precision of the system, does not measurably change while in the loop. So using time to seed multiple generators in tight succession is a common mistake. – AnorZaken Sep 22 '15 at 16:18
  • 2
    @AnorZaken but using a different (slower) method to seed the multiple random number generator instances is a poor solution. The good solution is to reuse a single instance of the random number generator. – phoog Nov 05 '15 at 04:46
  • @phoog Absolutely, but many others have already pointed this out in other answers and comments so I was just adding the explanation as to _why_ OP's code doesn't work. (Also it was addressing Chris to explain to him why `new Random()` is not random in this context and why.) This is important information in situations where you actually have a valid reason to create multiple instances of Random (such as creating multiple threads each with their own Random instance where it might not be desirable to have all the threads get the same random seed). – AnorZaken Nov 05 '15 at 16:46
  • If you really must use some form of randomness for seed generation, consider using a true random number generator like Random.org. Otherwise (unless you have some special context like two applications launching at the same time), new Random() should do the trick. Also, the seed used, if I'm not mistaken uses the pid and the parent's pid (at least in .Net)... – Andrew Apr 02 '16 at 09:17
  • 1
    If you need this, you're introducing a lot of extra overhead by reseeding each time and probably want something simpler. – McKay Feb 24 '17 at 00:31
  • 1
    Simple test to confirm (remove the seed from the constructor to get consistent exceptions): `var dict = new System.Collections.Concurrent.ConcurrentDictionary(); Parallel.For(0, 2, (_) => { bool success = dict.TryAdd(new Random(Guid.NewGuid().GetHashCode()).Next(), 0); if (!success) { throw new Exception("Duplicate!"); } });` – kevinpo May 11 '20 at 20:08
  • Man I was pulling my hair out over a bug where the seed is system time so two consecutive rands is always the same. I thought I was getting ridiculously unlucky. Then I realized the time is probably the same -__- why do most rand answers recommend using the time as seed? Horrible idea – pete May 14 '22 at 01:39
  • 1
    This doesn't really solve anything. Guids are as random as randoms – JSON Oct 03 '22 at 16:14
  • 1
    This is bad. Check accepted answer for real solution and learn why this is so bad. – Leandro Bardelli Mar 04 '23 at 01:28
125

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);
Mehrdad Afshari
  • 414,610
  • 91
  • 852
  • 789
  • 1
    Hi, I have got a confusion about the word 'Seed', How does it work? and what is the impact that it has on the Random Class in Java.util – gmhk Feb 23 '10 at 08:10
  • 22
    @harigm: Normally, a (pseudo-)random number generator is a deterministic algorithm that given an initial number (called *seed*), generates a sequence of numbers that adequately satisfies statistical randomness tests. Since the algorithm is deterministic, the algorithm will always generate the exact same sequence of numbers if it's initialized with the same seed. That's why system time (something that changes all the time) is usually used as the seed for random number generators. – Mehrdad Afshari Feb 23 '10 at 21:49
  • Re-seeding a random generator may be required when predictibility becomes an issue (say. online gambling). In that case, apart from using a truer random generator (like a lava lamp), you should reseed faster than pattern recognition can apply from an attacker side - or use a pool of short-lived generators (and choose randomly, and ensure no two generators are seeded with the same value, and much more) – PPC Apr 30 '19 at 14:35
32

Bit late, but the implementation used by System.Random is Environment.TickCount:

public Random() 
  : this(Environment.TickCount) {
}

This avoids having to cast DateTime.UtcNow.Ticks from a long, which is risky anyway as it doesn't represent ticks since system start, but "the number of 100-nanosecond intervals that have elapsed since 12:00:00 midnight, January 1, 0001 (0:00:00 UTC on January 1, 0001, in the Gregorian calendar)".

Was looking for a good integer seed for the TestApi's StringFactory.GenerateRandomString

Orphid
  • 2,722
  • 2
  • 27
  • 41
  • 1
    If it's a testApi, just use the number 4, it's deterministic and easy to test – hashtable Apr 21 '17 at 06:34
  • 2
    @hashtable that's often a good idea, but not all testing is unit testing. In system/integration testing introducing less predictable behaviour can increase the test surface - useful if you don't have the resources to check every possible input in a single test run. – Orphid Apr 21 '17 at 06:39
  • 1
    We encountered problems in our app, where parallel threads were being released simultaneously (by accident), and the result was that the threads each got the same seed for random because they were triggered in the same tick. This doesn't seem to happen with the Guid trick. – Chaos Crafter Dec 15 '20 at 22:47
16

In case you can't for some reason use the same Random again and again, try initializing it with something that changes all the time, like the time itself.

new Random(new System.DateTime().Millisecond).Next();

Remember this is bad practice though.

EDIT: The default constructor already takes its seed from the clock, and probably better than we would. Quoting from MSDN:

Random() : Initializes a new instance of the Random class, using a time-dependent default seed value.

The code below is probably your best option:

new Random().Next();
PPC
  • 1,734
  • 1
  • 21
  • 41
  • what about this? new Random(DateTime.Now.Millisecond).Next() As it gets the current milisecond. I like your idea of "initializing with something that changes all the time, like the time itself" though. Plus if we add a Thread.Sleep(1) in each iteration, it will be truely random. – Omidoo Sep 27 '12 at 17:04
  • Don't be too fast, it's still very bad randomness, just a little less predictable. One reason is because our milliseconds will never yield more than 1000 values, thus 1000 different random sequences instead of the 2^31 you probably expect. – PPC Sep 27 '12 at 23:05
  • 5
    You'll get a (little) better randomness by seeding Random with a larger not-too-predictable number, like new Random((int)DateTime.Now.Ticks) – PPC Oct 29 '12 at 21:27
  • 3
    I believe the default seed is ticks since system start time, anyway. – Ronnie Overby May 07 '13 at 01:41
  • 4
    If the Random class is initialized multiple times in the same millisecond (like in a quick loop), this won't help at all. `DateTime.Now.Ticks` also doesn't update quickly enough. – Christian Davén May 23 '14 at 06:54
  • 1
    The same problem as new Random(), which "Initializes a new instance of the Random class, using a time-dependent default seed value." – James May 30 '14 at 10:19
  • The default used seed is NOT better, I've compared it without a seed vs milliseconds as seed and the ms result was atleast partially random throughout calls only milliseconds apart where as the seedless one was not random at all in the same circumstances. The above suggested Guid one though always presented a random value even with extreme rapid calling, so that one's the best choice. – BloodyRain2k Jan 30 '17 at 17:38
  • @ChristianDavén - In a quick loop, if you're not concerned by performance, insert a Sleep() in your loop as Omidoo suggests. Else, you'd probably want to keep the same instance for some time and reinitialize it only when predictibility is an issue (like every 20 iterations or so). It all depends on your needs – PPC Apr 30 '19 at 14:30
5
public static Random rand = new Random(); // this happens once, and will be great at preventing duplicates

Note, this is not to be used for cryptographic purposes.

McKay
  • 12,334
  • 7
  • 53
  • 76
  • 7
    Note that unlike Java, `Random` in .NET is not thread-safe. Calling `Next` without appropriate locking mechanisms on different threads might cause corruption of the internal state of the random number generator. – Mehrdad Afshari Nov 23 '09 at 20:37
  • 2
    @Mehrdad: Or worse; I've had it throw exceptions. – Jason Nov 23 '09 at 20:52
  • 3
    @Jason: in most cases, getting an exception is better than dealing with bad results. I'd rather have my online poker application crashing than being easily predictable – PPC Oct 29 '12 at 21:29
  • 2
    @PPC in that scenario you should go for [crypto random](http://msdn.microsoft.com/en-us/library/system.security.cryptography.randomnumbergenerator(v=vs.110).aspx) – felickz Mar 05 '14 at 12:42
  • The OP said nothing about thread safety. Just calling fast. – McKay Feb 24 '17 at 00:29
1

A good seed initialisation can be done like this

Random rnd = new Random((int)DateTime.Now.Ticks);

The ticks will be unique and the cast into a int with probably a loose of value will be OK.

ZedZed
  • 27
  • 1
0

this workes for me:

private int GetaRandom()
    {
        Thread.Sleep(1);
        return new Random(DateTime.Now.Millisecond).Next();
    }
Omidoo
  • 493
  • 1
  • 6
  • 14
  • 8
    Putting the current thread to sleep can cause a multitude of problems with concurrency. You're essentially locking the current thread you're working with, which I suspect in most cases will be your main application thread. To make this work, I would suggest isolating your RNG into it's own thread, so that it can be considered thread-safe, and using it asyncronously. – Apache Mar 29 '16 at 02:23
-2

I use this for most situations, keep the seed if there is a need to repeat the sequence

    var seed = (int) DateTime.Now.Ticks;
    var random = new Random(seed);

or

    var random = new Random((int)DateTime.Now.Ticks);
Gary Davies
  • 920
  • 15
  • 12