tags:

views:

572

answers:

5

I have been writing some C# code for a training exercise, in which I had to create an array of random rectangles.

Problem being that the rectangle being produced by my GetRandomRectangle function was always the same. I was using System.Random to generate the coordinates for the rectangle.

I've realised that it was because the Random object was beign created with the default constructor, and so had the same seed. I've modified it to get a different seed for each rectangle now, and it works fine.

The question is - how does it decide on the 'default seed'? I've noticed that it doesn't seem to change over time either, a rectangle created with seed 2 will always be given the same dimensions.

It's probably something that I could Google, but it's nice to hear opinions and info from you guys as well.

Thanks :)

+10  A: 

The default seed is taken from the system clock.

I'm guessing that your GetRandomRectangle method was being called in quick succession and instantating a new instance of Random each time. When you do this, each instance of Random will take the same seed from the system clock, which is why your method created the same rectangle each time.

One solution is to create one instance of Random and pass that into your method:

Random rng = new Random();

Rectangle foo = GetRandomRectangle(rng);
Rectangle bar = GetRandomRectangle(rng);
Rectangle baz = GetRandomRectangle(rng);

// ...

public Rectangle GetRandomRectangle(Random rng)
{
    // create the rectangle using rng
}
LukeH
Even when I do this, and I run my program, then close it, then run it again with a few seconds in between, it seems to produce the same set of rectangles. Interesting...
Fiona Holder
Because it uses timestamp as the seed. It should use tickcount instead to guarantee not to get same seed.
Cem Kalyoncu
@cemkalyoncu: The default `Random` constructor uses `Environment.TickCount` as the seed. I don't think that's the issue here.
LukeH
A: 

When you use a seed, this means that you want the same sequence starting from that seed

Try the constructor without seed

Ahmed Khalaf
+1  A: 

Actually, the default Random() constructor is time-dependant and should provide different output upon running the application a second time. If you were getting the same rectangle every time, something else must have been going on.

Providing the seed manually will always give you the same sequence of pseudo-random numbers.

You should only need to instantiate a single Random object to generate all your random numbers. Don't create a new instance for each rectangle.

Thorarin
@Thorarin: If you create multiple `Random` instances in quick succession (eg, in a tight loop) then they'll use the same seed: In that situation the system clock isn't ticking fast enough to provide a unique value for each instance.
LukeH
@Luke: hence my comment on using a single instance.
Thorarin
+1  A: 

I used to use that as well, but I found the class to produce far from sufficiently random values. I switched to the random functions within the cryptography namespace instead. Here's a VERY simple version without error checking or screen size conversion:

     byte[] randomBytes = new byte[4];
     RandomNumberGenerator numberGenerator = System.Security.Cryptography.RandomNumberGenerator.Create();
     numberGenerator.GetNonZeroBytes(randomBytes);
     int x = randomBytes[0];
     int y = randomBytes[1];
     int width = randomBytes[2];
     int height = randomBytes[3];
     System.Drawing.Rectangle block = new Rectangle(x, y, width, height);
Bernhard Hofmann
The Random class produces random numbers that is sufficient for most uses, if you use it correctly. The cryptography random generator is only needed when you need exceptionally good randomness, like for creating encryption keys.
Guffa
A: 

Im no C# expert but this might work.

 public Rectangle GetRandomRectangle()
 {
      static Random rng=new Random();
      // create the rectangle using rng
 }
Cem Kalyoncu