关于c#:随机而非随机

Random not that random

本问题已经有最佳答案,请猛点这里访问。

我用随机数生成一个随机数序列。我只是构造一次随机对象,然后在循环中生成随机值(其中300个)。问题是,一旦我得到所有的值并对它们进行排序,我就会意识到其中一些值是相等的和/或是连续的:我生成的数字是从0到50000。

这是我的剧本:

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

有人能知道为什么会发生这种情况吗?我该如何改进这种情况,使之更加随机?


这就是生日悖论*。从50000中抽取300个数字时,其中至少两个数字相等的近似概率为

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

(我可以算出确切的概率,但我很懒!)

所以,发生碰撞的可能性更大。顺序更可能(现在不需要碰撞,只需要n - 1nnn + 1被某些n击中)。

随机是易变的。

*如果你不熟悉它,它说如果一个房间里有23个人,那么至少有两个人共享同一个生日的可能性更大。

!好吧,我算出来了。是0.59538305549951746819986449….


研究:

嗨,伙计们,

如果使用不带参数new Random()的构造函数,则种子取决于当前服务器时间。

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

所以,如果我这样尝试:

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

在一千次通话中,我只收到三个不同的号码,大约300次!不是那么随机…

在构造函数new Random(0)中设置种子将返回一个固定的数字序列。

例如,new Random(0).Next(50)总是这样!返回36。如果你不相信我,你自己试试看;

对于"实数"随机数,我们需要的是一个不断变化的种子,它与时间无关。

我正在使用更改值的哈希代码:

例如:Guid.NewGuid().GetHashCode()DateTime.Now.GetHashCode()

结果:

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

或(为了获得更好的性能):

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

ps:下一个(max)方法的最大值总是max-1;

->run.next(11)可以返回0、1、2、…、8、9、10。不是11!

问候Bahamut=)


作为解释为什么你会偶尔看到重复,杰森的回答是对的。

如果你想要的是300个不同的随机数,那么这样的数字怎么样?

1
2
3
4
5
6
7
8
9
10
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);