1

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 :)

Fiona - myaccessible.website
  • 14,481
  • 16
  • 82
  • 117
  • How does it decide on a default seed? Not randomly according to your findings! -of course, there is no such thing as random, but that's an altogether different discussion. – Bryan Sep 17 '09 at 10:08
  • Duplicate: http://stackoverflow.com/questions/807892/why-does-this-method-return-the-same-random-string-each-time – Guffa Sep 17 '09 at 10:24
  • I was aware of that question, and don't feel that it is a duplicate. That user wanted to know why their code wasn't working. I am aware that it is because of the seed, and wanted to know more about the mechanisms used in the random number generation. – Fiona - myaccessible.website Sep 17 '09 at 10:53

5 Answers5

11

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
  • 263,068
  • 57
  • 365
  • 409
  • 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 - myaccessible.website Sep 17 '09 at 11:35
  • Because it uses timestamp as the seed. It should use tickcount instead to guarantee not to get same seed. – Cem Kalyoncu Sep 17 '09 at 11:40
  • 1
    @cemkalyoncu: The default `Random` constructor uses `Environment.TickCount` as the seed. I don't think that's the issue here. – LukeH Sep 17 '09 at 12:01
1

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
  • 47,289
  • 11
  • 75
  • 111
  • @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 Sep 17 '09 at 10:10
  • @Luke: hence my comment on using a single instance. – Thorarin Sep 17 '09 at 10:59
1

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
  • 10,321
  • 12
  • 59
  • 78
  • 3
    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 Sep 17 '09 at 10:17
0

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,220
  • 12
  • 28
0

Im no C# expert but this might work.

 public Rectangle GetRandomRectangle()
 {
      static Random rng=new Random();
      // create the rectangle using rng
 }
Cem Kalyoncu
  • 14,120
  • 4
  • 40
  • 62