9

Hello i am having some problems generating random numbers with C# Now i have this function.

public Color getRandomColor()
{
    Color1 = new Random().Next(new Random().Next(0, 100), new Random().Next(200, 255));
    Color2 = new Random().Next(new Random().Next(0, 100), new Random().Next(200, 255));
    Color3 = new Random().Next(new Random().Next(0, 100), new Random().Next(200, 255));
    Color color = Color.FromArgb(Color1, Color2, Color3);
    Console.WriteLine("R: " + Color1 + " G: " + Color2 + " B: " + Color3 + " = " + color.Name);
    return color;
}

Now you might notice that there are ALOT of new Random() there, that is because i want to weed out the probability that it could be a same instance error.

I now run this function 8 times, a couple of times. Now here are the out puts.

R: 65 G: 65 B: 65 = ff414141
R: 242 G: 242 B: 242 = fff2f2f2
R: 205 G: 205 B: 205 = ffcdcdcd
R: 40 G: 40 B: 40 = ff282828
R: 249 G: 249 B: 249 = fff9f9f9
R: 249 G: 249 B: 249 = fff9f9f9
R: 94 G: 94 B: 94 = ff5e5e5e
R: 186 G: 186 B: 186 = ffbababa

R: 142 G: 142 B: 142 = ff8e8e8e
R: 190 G: 190 B: 190 = ffbebebe
R: 19 G: 19 B: 19 = ff131313
R: 119 G: 119 B: 119 = ff777777
R: 119 G: 119 B: 119 = ff777777
R: 75 G: 75 B: 75 = ff4b4b4b
R: 169 G: 169 B: 169 = ffa9a9a9
R: 127 G: 127 B: 127 = ff7f7f7f

R: 73 G: 73 B: 73 = ff494949
R: 27 G: 27 B: 27 = ff1b1b1b
R: 125 G: 125 B: 125 = ff7d7d7d
R: 212 G: 212 B: 212 = ffd4d4d4
R: 174 G: 174 B: 174 = ffaeaeae
R: 0 G: 0 B: 0 = ff000000
R: 0 G: 0 B: 0 = ff000000
R: 220 G: 220 B: 220 = ffdcdcdc

As you can see this is not so random again, but why dose this happens? and how can i counter it?

Androme
  • 2,399
  • 4
  • 43
  • 82
  • I had this same issue generating random colours in a normalised range. A quick way without providing a seed is to permute a couple values together using the same random stream. Lack of precision but can be used to get a slightly more varied random distribution. E.g. int x = rng.Next() ^ rng.Next(); int magnitude = x * x; float value = x / (float)magnitude; –  Aug 05 '17 at 04:13
  • Using this method you can generate a slightly better colour distribution by the following. Color = colour = new Color( (byte)(rand.Next(0, 255) ^ rand.Next(0, 255)), (byte)(rand.Next(0, 255) ^ rand.Next(0, 255)), (byte)(rand.Next(0, 255) ^ rand.Next(0, 255)), (byte)(rand.Next(0, 255) ^ rand.Next(0, 255))) –  Aug 05 '17 at 04:33

4 Answers4

28

You're creating a new Random for each single value you need.

Try creating a unique Random object and calling the .Next() function multiple times.

public Color getRandomColor()
{
    Random rand = new Random();

    Color1 = rand.Next(rand.Next(0, 100), rand.Next(200, 255));
    Color2 = rand.Next(rand.Next(0, 100), rand.Next(200, 255));
    Color3 = rand.Next(rand.Next(0, 100), rand.Next(200, 255));
    Color color = Color.FromArgb(Color1, Color2, Color3);
    Console.WriteLine("R: " + Color1 + " G: " + Color2 + " B: " + Color3 + " = " + color.Name);
    return color;
}

Taken from MSDN documentation on Random object :

By default, the parameterless constructor of the Random class uses the system clock to generate its seed value, while its parameterized constructor can take an Int32 value based on the number of ticks in the current time. However, because the clock has finite resolution, using the parameterless constructor to create different Random objects in close succession creates random number generators that produce identical sequences of random numbers

Thibault Falise
  • 5,795
  • 2
  • 29
  • 32
  • 4
    Yep, this is the answer. Instances of Random created very quickly one after the other have a tendency to give the same value. I assume that this is because they get seeded by the computer clock, but that's nothing more than wild conjecture. – David Rutten Apr 28 '10 at 07:36
  • 1
    Exactly. Random has 2 constructors. The parameterless one takes uses the current time as the seed. You can also use the one that takes an integer. So it will use the argument you pass as the seed. – empz Apr 28 '10 at 07:38
  • My code looked like that in the beginngin, we created the many instance to see if that helper. But now we get R: 164 G: 78 B: 145 = ffa44e91 R: 206 G: 20 B: 149 = ffce1495 R: 206 G: 20 B: 149 = ffce1495 R: 73 G: 60 B: 94 = ff493c5e R: 147 G: 94 B: 101 = ff935e65 R: 212 G: 123 B: 61 = ffd47b3d R: 98 G: 79 B: 70 = ff624f46 R: 85 G: 110 B: 79 = ff556e4f It is a bit more random, but if you see result 2 and 3 are they the same. – Androme Apr 28 '10 at 07:48
  • Hehe ok, i have now created it as an static variable that is used. and this work now, thanks static Random random = new Random(); int Color1, Color2, Color3; public Color getRandomColor() { Color1 = random.Next(0, 255); Color2 = random.Next(0, 255); Color3 = random.Next(0, 255); Color color = Color.FromArgb(Color1, Color2, Color3); Console.WriteLine("R: " + Color1 + " G: " + Color2 + " B: " + Color3 + " = " + color.Name); return color; } – Androme Apr 28 '10 at 07:57
  • See my edited answer using a different seed for every Random instance. – empz Apr 28 '10 at 07:58
7

Each new Random() is seeded with the current time.

If you create several Random instances in quick succession, and your machine runs it fast enough that they are close enough together to get the same seed, they will return the same sequence of values!

Use a single Random, calling .Next() to get each value.

Now you might notice that there are ALOT of new Random() there, that is because i want to weed out the probability that it could be a same instance error.

This is a fallacy; a stream of numbers from a single Random is evenly distributed - effort has gone into making it random.

Will
  • 73,905
  • 40
  • 169
  • 246
5

You are creating many Random objects sequentially, which causes them to be seeded with the same/almost the same timestamp. Thus generating random numbers but equal among them.

Try creating a single instance of Random and using that for all your Random number needs.

Francisco Soto
  • 10,277
  • 2
  • 37
  • 46
1

Random works better when using one instance of it.

Try this:

public Color getRandomColor()
{
    var random = new Random();
    Color1 = random.Next(random.Next(0, 100), random.Next(200, 255));
    Color2 = random.Next(random.Next(0, 100), random.Next(200, 255));
    Color3 = random.Next(random.Next(0, 100), random.Next(200, 255));
    Color color = Color.FromArgb(Color1, Color2, Color3);
    Console.WriteLine("R: " + Color1 + " G: " + Color2 + " B: " + Color3 + " = " + color.Name);
    return color;
}
empz
  • 11,509
  • 16
  • 65
  • 106
  • How is the edit anything but slower than using a single random? Its certainly not 'more random'? – Will Apr 28 '10 at 08:06
  • 1
    It will even helpfully return the same "random" color every time the function is called. – Miles Apr 28 '10 at 08:19