1

Possible Duplicate:
Random number generator only generating one random number

I've distilled the behavior observed in a larger system into this code sequence:

for (int i = 0; i < 100; i++)
{
    Random globalRand = new Random(0x3039 + i);

    globalRand.Next();
    globalRand.Next();
    int newSeed = globalRand.Next();

    Random rand = new Random(newSeed);
    int value = rand.Next(1, 511);
    Console.WriteLine(value);
}

Running this from Visual Studio 2012 targeting .NET 4.5 will output either 316 or 315. Extending this beyond 100 iterations and you'll see the value slowly decrement (314, 313...) but it still isn't what I'd imagine anyone would consider "random".

EDIT

I am aware that there are several questions on StackOverflow already that ask why their random numbers aren't random. However, those questions have issues regarding one of a) not passing in a seed (or passing in the same seed) to their Random object instance or b) doing something like NextInt(0, 1) and not realizing that the second parameter is an exclusive bound. Neither of those issues are true for this question.

Community
  • 1
  • 1
Tinister
  • 11,097
  • 6
  • 35
  • 36
  • @Kirk I disagree. The problem displayed in that question was that he wasn't seeding the Random class, so it was using the same "tick count" as the seed. I'm giving my classes a unique seed value. – Tinister Oct 15 '12 at 18:53
  • 3
    Are you trying to make something more random than random. That's ill advised. Why not seed once only? – spender Oct 15 '12 at 18:53
  • Why is a local variable called `globalRand`? – Adam Oct 15 '12 at 18:56

4 Answers4

5

It's a pseudo random generator which basically creates a long (infinite) list of numbers. The list is deterministic but the order can in most practical scenarios be treated as random. The order is however determined by the seed.

The most random behaviour you can achieve (without fancy pants tricks that are hard to get right all the time) is to reuse the same object over and over.

If you change your code to the below you have a more random behaviour

Random globalRand = new Random();

for (int i = 0; i < 100; i++)
{
    globalRand.Next();
    globalRand.Next();
    int newSeed = globalRand.Next();

    Random rand = new Random(newSeed);
    int value = rand.Next(1, 511);
    Console.WriteLine(value);
}

The reason is the math behind pseudo random generators basically just creates an infinite list of numbers.

The distribution of these numbers are almost random but the order in which they come are not. Computers are deterministic and as such incapable of producing true random numbers (without aid) so to circumvent this math geniuses have produced functions capable of producing these lists of numbers, that have a lot of radnomness about them but where the seed is determining the order.

Given the same seed the function always produces the same order. Given two seeds close to each order (where close can be a property of which function is used) the list will be almost the same for the first several numbers in the list but will eventually be very different.

Rune FS
  • 21,497
  • 7
  • 62
  • 96
  • 1
    Well, yes. Remember that my example code is a distillation of the behavior of a larger system. There are countless ways I can reorganize the system to avoid this very specific behavior... but I shouldn't need to care. Do you know why it behaves this way? – Tinister Oct 15 '12 at 19:00
  • 1
    @Tinister well basically because you didn't care sorry but in with pseudo random generators it is really important to care sbout how you construct your objects. You should in most cases have just one for your application. See up date for an extended explanation – Rune FS Oct 15 '12 at 19:03
  • @RuneFS Note that `Random` isn't thread safe, and synchronizing access to just one in a highly multithreaded environment will hurt performance. Getting random numbers in those cases is...harder. – Servy Oct 15 '12 at 19:20
  • `Given to seeds close to each order (where close can be a property of which function is used) the list will be almost the same for the first several numbers in the list`. If this is true, then this would seem to be the answer to the OP's problem. – Matt Burland Oct 16 '12 at 13:44
  • Why does Microsoft keep thisuseless function within the API? it is a huge security problem for all people expecting a reliable random number generator. – cskwg Aug 16 '20 at 08:03
  • @cskwg I wouldn't know why MS has decided to do this but it's a rather common practice and does have some upsides. Such as predictable testing. The issue isn't that big. It's only ever going to be an issue if you pass and argument. And as with any function, you shouldn't blindly pass arguments without understanding their significance first. – Rune FS Aug 17 '20 at 09:19
  • @RuneFS: I did some testing in a tight loop, generating 1,000,000 numbers. The results were not perfect. I found another solution, using RNGCryptoServiceProvider which was very a reliable. Performance did not matter in this case, but it was similar. – cskwg Aug 19 '20 at 05:58
1

Using the first random number to generate the second. Doesnt make it any more "Random". As suggested try this.

Also as suggested no need to generate the random object inside the loop.

    Random globalRand = new Random();

    for (int i = 0; i < 100; i++)
    {
        int value = globalRand.Next(1, 511);
        Console.WriteLine(value);
    }
LiamB
  • 18,243
  • 19
  • 75
  • 116
  • 1
    This is true, but it shouldn't make it less random either, should it? – Matt Burland Oct 15 '12 at 18:53
  • @Matt but declaring `globalRand` within the loop makes it a *lot* less random. – Adam Oct 15 '12 at 19:00
  • @codesparkle: Yes, but it's declared each time with a *different* seed. So it shouldn't give the same result. – Matt Burland Oct 15 '12 at 19:01
  • 2
    @MattBurland It might not give the exact same result every time if you give it a different seed, but it still won't be as uniformly distributed. If you only get one value per seed you essentially have one giant map where each seed results in one value. That will only be as random as the seeds are random, and in your case the seeds aren't random, the're based on a index. – Servy Oct 15 '12 at 19:16
  • Not uniform is one thing, but according to the OP: `output either 316 or 315` – Matt Burland Oct 15 '12 at 19:19
0

Without parameters Random c'tor takes the current date and time as the seed - and you can generally execute a fair amount of code before the internal timer works out that the current date and time has changed. Therefore you are using the same seed repeatedly - and getting the same results repeatedly. Source : http://csharpindepth.com/Articles/Chapter12/Random.aspx

sgud
  • 422
  • 2
  • 7
0

I believe the Random() is time based so if your process is running really fast you will get the same answer if you keep creating new instances of your Random() in your loop. Try creatining the Random() outside of the loop and just use the .Next() to get your answer like:

Random rand = new Random(); 

for (int i = 0; i < 100; i++) 
{ 
    int value = rand.Next(); 
    Console.WriteLine(value); 
} 
Jmyster
  • 965
  • 2
  • 9
  • 27
  • 1
    The original code doesn't use Random(), it always passes a seed that changes on each loop. Also, you are using newSeed outside of it's scope. – Matt Burland Oct 15 '12 at 19:04