24

Consider this method:

private static int GenerateRandomNumber(int seed, int max)
{
   return new Random(seed).Next(max);
}

On my machine, executing this loop yields the same number through 1500 iterations:

  for (int i = 0; i < 1501; i++)
            {
                int random = GenerateRandomNumber(100000000, 999999999);
                Console.WriteLine(random.ToString());
                Console.ReadKey();
            }

I get 145156561, for every single iteration.

I don't have a pressing issue, I was just curious about this behavior because .Next(max) says "Returns a Non Negative random number less than the specified maximum. Perhaps I am not understanding something basic.

Ta01
  • 31,040
  • 13
  • 70
  • 99

7 Answers7

47

You're always seeding a new instance with the same seed, and then grabbing the first max. By using a Seed, you're guaranteeing the same results.

If you want to have a static, random number generation that does different results, you should rework this a bit. However, since Random is not threadsafe, it requires some synchronization when used statically. Something like:

private static Random random;
private static object syncObj = new object();
private static void InitRandomNumber(int seed)
{
     random = new Random(seed);
}
private static int GenerateRandomNumber(int max)
{
     lock(syncObj)
     {
         if (random == null)
             random = new Random(); // Or exception...
         return random.Next(max);
     }
}
Reed Copsey
  • 554,122
  • 78
  • 1,158
  • 1,373
  • 3
    This will probably kill the PC if you need many random numbers :-) At least use the SpinLock if you are under C# 4.0, or make the Random object Thread Static. – xanatos Mar 10 '11 at 19:06
  • You should use double-check locking. – SLaks Mar 10 '11 at 19:08
  • 1
    @SLaks: Doesn't really help - Random.Next() is not thread safe, so you always need a lock. The lock here isn't for lazy instantiation... – Reed Copsey Mar 10 '11 at 19:10
  • @xanatos: True- This is not something I would recommend if you are using this from many threads. In that case, a ThreadLocal would like be a better option, but that has its own unique issues I would avoid unless required. – Reed Copsey Mar 10 '11 at 19:10
  • @Reed: You're write; I was thinking about `[ThreadStatic]`. – SLaks Mar 10 '11 at 19:11
  • @SLaks: BTW - I'd recommend `ThreadLocal` over using [ThreadStatic] - http://msdn.microsoft.com/en-us/library/dd642243.aspx Much nicer usage semantics – Reed Copsey Mar 10 '11 at 19:14
  • Yes, (although it's a little slower) – SLaks Mar 10 '11 at 19:14
  • 6
    As a free bonus, I'll add an article of Jon Skeet on Random AND ThreadLocal! :-) http://csharpindepth.com/Articles/Chapter12/Random.aspx – xanatos Mar 10 '11 at 19:19
9

Dilbert has encountered the same problem back in 2001:

http://dilbert.com/strips/comic/2001-10-25/

Coincidence?

I don't think so.

And random.org agrees : http://www.random.org/analysis/

dbrin
  • 15,525
  • 4
  • 56
  • 83
  • 7
    There is no room for humor in SO, really? – dbrin Jan 30 '14 at 16:29
  • While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes. - [From Review](/review/low-quality-posts/18480928) – jv42 Jan 10 '18 at 20:01
  • With all due respect @jv42 but I cant reproduce the comic strip content, so in this case a link is justified. – dbrin Jan 10 '18 at 23:33
  • You can't and it's probably not useful. You're posting an answer here, which should contain helpful content to solve a problem. The original question contained a bug in some code used to generate random numbers, it was not about RNGs theory. – jv42 Jan 11 '18 at 14:44
  • Although I appreciate the humor, and Dilbert in particular, I just think your 'answer' isn't helpful. – jv42 Jan 11 '18 at 14:45
6

The problem is that you are creating a new Random instance with the same seed number each time. You should create a single Random instance (store it in a static if necessary) and simply call the next method on that same instance.

Random number generation is not truly random, see this Wikipedia entry for more details.

Eric Giguere
  • 3,495
  • 15
  • 11
4

Salam to All, Well it drove me crazy as well. The answer is simple. Change the seed before you generate random.

Example: I want to generate random number between 1 to 10

Random rnd = new Random(DateTime.Now.Second);
int random_number = rnd.Next(10);

Put it inside a loop and run it three times. It will give out random numbers below 10.

Gregory
  • 6,514
  • 4
  • 28
  • 26
Talha
  • 1,546
  • 17
  • 15
  • For anyone who stumbled upon this, this does not work because the seed will not be unique if the iteration is large enough. – C O Jul 13 '19 at 01:05
3

Pseudo-random number generator usually work by choosing a seed, and then generating a deterministic sequence based on that seed. Choosing the same seed every time, you generate the same sequence.

There are "only" 2^32 different random sequences in .NET.

Jens
  • 25,229
  • 9
  • 75
  • 117
3

Not sure how the internals work.. check wiki for it, but it's very simple.

public class MathCalculations
{
    private Random rnd = new Random();

    public Int32 getRandom(Int32 iMin, Int32 iMax)
    {
        return rnd.Next(iMin, iMax);
    }
}

public class Main
{
    MathCalculations mathCalculations = new MathCalculations();
    for (int i = 0; i < 6; i++)
    {
        getRandom(0,1000);
    }
}

will generate Number1, Number2, Number3, Number4, Number5, Number6 (1 seed, 1 sequence of many numbers, random*not really, but approx.*)

if you however do this:

public class MathCalculations
{
    public Int32 getRandom(Int32 iMin, Int32 iMax)
    {  
        Random rnd = new Random();
        return rnd.Next(iMin, iMax);
    }
}

public class Main
{
    MathCalculations mathCalculations = new MathCalculations();
    for (int i = 0; i < 6; i++)
    {
        getRandom(0,1000);
    }
}

You will now get Number1, Number1, Number1, Number1, Number1, Number1 (1 seed, 6 equal sequences of many numbers, always pick the same starting number from each equal sequence).. At some point Number1 will be different, because the seed changes over time.. but you need to wait some time for this, nonetheless, you never pick number2 from the sequence.

The reason is, each time you generate a new sequence with the same seed, hence the sequence is the same over and over again, and each time your random generated will pick the first number in it's sequence, which, with the same seed, is of course always the same.

Not sure if this is technically correct by the underlying methods of the random generator, but that's how it behaves.

user957537
  • 31
  • 1
1

In the event that anyone is looking for a "quick and dirty" "solution" (and I use that term with caution) then this will suffice for most.

int secondsSinceMidnight = Convert.ToInt32(DateTime.Now.Subtract(DateTime.Today).TotalSeconds);
Random rand = new Random(secondsSinceMidnight); 
var usuallyRandomId = rand.Next();

Please note my use of usually random. I agree that the item marked as the answer is a more correct way of doing this.

AnthonyJ
  • 435
  • 1
  • 7
  • 9