【问题标题】:Random not that random [duplicate]随机而不是随机[重复]
【发布时间】:2011-06-19 00:43:57
【问题描述】:

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

这是我的脚本:

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

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

【问题讨论】:

  • 您需要具体说明如何定义“更随机”
  • 为什么要对随机数进行排序?这不是违背了生成随机数的目的吗?
  • 我不是数学家,但在我看来,在对 0 到 50000 之间的 300 个随机数列表进行排序后,至少有几个不会是相等或顺序。
  • 为什么要对随机值进行排序?只是为了测试它们的分布吗?这可能与Birthday paradox 有关
  • 您是否希望数字在 10、110、210、310 等范围内等距分布?这似乎不那么随机了。

标签: c# .net random


【解决方案1】:

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

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

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

因此,您很可能会发生碰撞。顺序更有可能(现在你不需要碰撞,你只需要n - 1nnn + 1 被击中一些n)。

随机是善变的。

*:如果你不熟悉的话,它说如果你在一个房间里有二十三个人,那么房间里至少有两个人的可能性很大生日相同。

!:好的,我解决了。它是 0.5953830515549951746819986449....

【讨论】:

    【解决方案2】:

    研究:

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

    Random(): "初始化 Random 类的新实例,使用时间相关" http://msdn.microsoft.com/en-us/library/system.random.aspx

    所以,如果我这样尝试:

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

    我在一千个电话中只收到大约 300 次 3 个不同的号码!不是那么随意...

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

    例如new Random(0).Next(50) always! 返回 36。如果您不信任我,请自行尝试;

    “真实”随机数需要的是一个不断变化的种子,它与时间无关。

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

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


    结果:

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

    或(为了更好的性能):

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

    PS:Next(max)-方法的最大值总是max - 1;

    -> ran.Next(11) 可以返回 0,1,2,...,8,9,10。不是 11 岁!

    【讨论】:

    • DateTime.Now.GetHashCode() 并不比默认种子好。
    • +1 这对我来说已经足够“随机”了 :) 当我尝试生成 2000 个数字时,没有数字团块。
    • @CodesInChaos 你的权利。我不知道 Random 的默认构造函数是否使用 DateTimes 哈希码或毫秒或其他什么,但它根本不是随机的
    • 我喜欢它,一个非常简单和模块化的解决方案
    • @Bahamut 您是否意识到不是您的新种子值修复了它,而是您将Random 实例的初始化移出循环?当试验之间只有一个变量发生变化时,试验最有效。
    【解决方案3】:

    作为为什么您会看到偶尔重复的解释,Jason's answer 是正确的。

    如果您想要是 300 个不同的随机数,那么这样的东西呢?

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

    【讨论】:

    • 是的,它给出了不同的数字,但它仍然有连词,这是由于我相信的生日悖论。这似乎满足了我需要做的事情。谢谢丹涛
    • 请记住,通过强制区分,您实际上是在损害“随机性”——分布不再(伪)均匀。
    • @bavaza:不确定该评论是针对我还是针对 OP,但我认为 OP 实际上并不想要真正的随机性;否则他不会问这个问题。当然你是正确的,消除重复会损害数据的随机性,就像排序一样。
    • @Dan:它针对的是 OP 和其他 SO 迷。我决定添加它,因为我经常发现人们倾向于滥用统计数据。无论如何,感谢您的回答:-)。
    • 非常适合伪随机列表感谢 DanTao
    猜你喜欢
    • 2020-05-13
    • 2011-09-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-03
    • 2015-07-12
    相关资源
    最近更新 更多