Random not that random [duplicate]

2019-01-19 19:01发布

This question already has an answer here:

I am using Random to generate a sequence of random number. I am constructing the random object just once and then inside the loop generating the random values (300 of them). The problem is that once I get all the values and do a sort on them I realize that some of them are equal and/or sequential: I am generating numbers from 0 to 50000.

This is my script:

Random rnd = new Random();
for (int n=0; n < 300; n++)
{
    int RndNumber = rnd.Next(0, 50000);
    System.Threading.Thread.Sleep(3);
}

Can someone have a clue on why this is happening, and how can I improve this to make it more random?

标签: c# .net random
3条回答
Emotional °昔
2楼-- · 2019-01-19 19:20

Research:

Hi guys,

if you use the constructor without parameters new Random() the seed is depending on the current servertime.

Random(): "Initializes a new instance of the Random class, using a time-dependent" http://msdn.microsoft.com/en-us/library/system.random.aspx

So, if I try it like this:

for(int i = 0; i < 1000; i++)
{
   Random ran = new Random();
   Console.WriteLine(ran.Next(50001));
}

I only get 3 different numbers about 300 times within a thousand calls! Not that random...

Setting the seed in the constructor new Random(0) returns a fix serie of numbers.

e.g. new Random(0).Next(50) always! returns 36. Try it yourself, if you don't trust me;

What we need for "real" random numbers is a changing seed, that's independent of time.

I'm using Hashcode of changing values:

e.g. Guid.NewGuid().GetHashCode() or DateTime.Now.GetHashCode()


Result:

Random ran = new Random(Guid.NewGuid().GetHashCode());
for(int i = 0; i < 1000; i++)
{       
   Console.WriteLine(ran.Next(50001));
}

or (for better performance):

for(int i = 0; i < 1000; i++)
{
     int val = Guid.NewGuid().GetHashCode() % 50001;
     val = val > 0 ? val : -val;
     Console.WriteLine(val);
}

PS: The maximum of the Next(max)-method is always max - 1;

-> ran.Next(11) can return 0,1,2,...,8,9,10. Not 11!

Greets Bahamut =)

查看更多
Anthone
3楼-- · 2019-01-19 19:22

So this is the birthday paradox*. When you draw 300 numbers from 50000 the approximate probability that at least two of them are equal is

p(300) = 1 - exp(-300 * 300 / (2 * 50000))
       = 0.59

(I could work out the exact probability but I'm lazy!.)

So, chances are more likely than not that you'll have a collision. Sequential is even more likely (now you don't need a collision, you just need n - 1 and n or n and n + 1 to be hit for some n).

Random is fickle.

*: In case you're not familiar with it, it says that if you have twenty-three people in a room, it is more likely than not that at least two people in the room share the same birthday.

!: Okay, I worked it out. It's 0.5953830515549951746819986449....

查看更多
不美不萌又怎样
4楼-- · 2019-01-19 19:23

As an explanation of why you're seeing the occasional duplicate, Jason's answer is right on.

If what you want is 300 distinct random numbers, what about something like this?

static IEnumerable<int> GetRandoms(int min, int max)
{
    var rand = new Random();
    while (true)
    {
        yield return rand.Next(min, max);
    }
}

var distinctRandoms = GetRandoms(0, 50000).Distinct().Take(300);
查看更多
登录 后发表回答