【问题标题】:Random number generator generating same numbers each time application is ran [duplicate]每次运行应用程序时随机数生成器生成相同的数字[重复]
【发布时间】:2014-05-07 21:25:33
【问题描述】:

我知道这个问题已被多次提出,但没有一个对我有用。

首先我在我的名为RandomNumGenerator(items)的方法中这样做了

List<int> randNum = new List<int>();
foreach (var item in items)
{
    randNum.Add(new Random(1000).Next());
}

这总是给我相同的号码,然后在查看this answer 之后,我这样做了:

Random rnd = new Random(1000);
foreach (var item in items)
{
    randNum.Add(rnd.Next());
}

这给了我如下数字

325467165 
506683626   
1623525913  
2344573     
1485571032

虽然这对于循环的每次迭代都很好,但这里的问题是,当我停止并重新运行应用程序时,我会再次得到与之前相同的数字。

325467165 
506683626   
1623525913  
2344573     
1485571032

这种行为仅在调试期间出现,还是每次我调用 RandomNumGenerator 时都会遇到同样的问题?

【问题讨论】:

  • 我建议你在类中声明rndstatic readonly 并重用同一个实例。
  • 这里有很多好的答案,因此很难选择正确的答案。我对 Neel 和 Tim Schmelter 给出的答案意见不一。虽然蒂姆的回答确实解决了我的问题,但尼尔斯的回答为我提供了解决未来可能出现的问题的方法。
  • 您正在为生成器播种相同的编号。省略该参数,它将从时钟派生一个种子。
  • 现在与问题无关,但请使用实际编译的代码以供将来使用。据我们所知,如果您不向我们展示为您提供结果的代码,问题可能出在任何地方。
  • 这个问题之前已经被问过很多次了。除了 OP 明显的混乱之外,我看不出这个实例有什么不同。

标签: c# .net random


【解决方案1】:

您在这里始终使用相同的种子 1000 为 Random 实例播种:

Random rnd = new Random(1000);

这不会这样做,因为当前时间被用作种子:

Random rnd = new Random();

看看constructor,它采用int

为不同的 Random 对象提供相同的种子值会导致 每个实例产生相同的序列随机数。

【讨论】:

    【解决方案2】:

    根据MSDN

    public Random(
        int Seed
    )
    

    种子

    用于计算伪随机数序列的起始值的数字。如果指定负数,则使用数字的绝对值。

    大多数初学者在涉及 RNG(随机数生成器)时出错的原因是对“种子”是什么以及它的作用缺乏了解。


    那么什么是“种子”?

    Random 类是用于生成伪随机数的类 - 或看似随机的数字。它们通常是一个数学函数,它使用一个参数——“种子”——来生成一系列看似随机的数字。

    new Random(1000)的情况下,前5个非负随机整数是

    325467165
    506683626
    1623525913
    2344573
    1485571032

    在您的第一个代码中,每次您需要一个随机数时,您都会使用相同的种子创建一个新的伪随机数序列,因此显然您的数组中填充了相同的数字:@987654326 @,恰好是new Random(1000)生成的第一个非负整数。

    这也解释了为什么您的第二个代码每次启动应用程序时总是生成相同的伪随机数序列。

    为确保您的应用始终生成不同的伪随机序列,您需要每次使用不同的种子。到目前为止,确保这一点的最简单方法是慢慢来

    Random rnd = new Random(DateTime.UtcNow.Millisecond);
    // Taking the millisecond component, because it changes quickly
    

    幸运的是,您不必输入这么多,因为 default constructor for the Random class 已经做了类似的事情。

    Random rnd = new Random(); // Much simpler, isn't it?
    

    请记住,Random不是线程安全的;如果多个线程尝试同时访问同一个 Random 对象,您的 RNG 在其剩余生命周期内将仅返回 0。

    另外需要注意的是,一个接一个地创建多个 Random 对象 - 即使使用时间作为种子 - 也会导致相同的伪随机数序列。

    Random r1 = new Random();
    Random r2 = new Random();
    Random r3 = new Random();
    Random r4 = new Random();
    

    在上述代码中,r1r2r3r4 都将生成相同序列的可能性非常高。

    这怎么可能?
    好吧,(不)幸运的是,CPU 的速度非常快。一个 1 GHz CPU 每秒可以执行大约 10 亿条指令(给予或接受);这是每 1 纳秒 1 条指令 - 或每 1 百万分之一毫秒 1 条指令。
    创建一个新的Random 对象可能需要相当多的指令,但绝对少于一百万个。


    如果使用时钟的当前毫秒计数是我们“所有人”想要的并且已经是默认值,为什么我们需要手动定义种子?

    因为它对于保持多个终端同步非常有用。

    想象一个游戏,其中随机出现重要现象,例如可能完全颠覆游戏的天气变化。您不会希望只有一侧受雾影响,而其余的仍然受益于晴朗的天气,对吧?

    当然,您可以让服务器或主机生成随机天气变化并通知玩家;或者您可以在游戏开始之前定义一个种子,并使用该种子来确保整个游戏中所有玩家的“随机性”相同。

    编码不好玩吗?

    【讨论】:

    • 支持自定义种子但不记录用于生成输出的算法是一个愚蠢的组合。当算法在版本之间或同一 API 的不同实现之间发生变化时会造成很多痛苦。
    【解决方案3】:

    你需要改变这个:

    Random rnd = new Random(1000);
    

    Random rnd = new Random();
    

    来自Random Constructor docs

    默认种子值来自系统时钟,具有有限的 解决。结果,在 通过调用默认构造函数的紧密继承将具有 相同的默认种子值,因此,将产生相同的 随机数集。这个问题可以通过使用单个 随机对象生成所有随机数。你也可以解决 它通过修改系统时钟返回的种子值,然后 将这个新的种子值显式地提供给 Random(Int32) 构造函数。有关详细信息,请参阅 Random(Int32) 构造函数。

    【讨论】:

      【解决方案4】:

      关键概念是随机种子 - Random 从中派生出其他一切的初始数据。如果种子相同,则“随机”序列将相同。

      默认情况下,种子设置为零,这显然会导致程序运行之间重复序列。

      为避免这种情况,您可以像这样构造 Random:

      Random rnd = new Random();
      

      ...在引擎盖下是:

      Random rnd = new Random(Environment.TickCount);
      

      这将在操作系统启动后的毫秒数内初始化 Random 对象。每次您的程序启动时,这都会有所不同,因此您每次都会得到不同的随机序列。

      【讨论】:

      • 这是 .NET 在默认构造函数内部所做的。
      • 对。编辑了我的答案
      【解决方案5】:

      Random .Next() 方法生成伪随机数。您应该声明并初始化一个随机对象,而不是每次都创建新对象。并且不需要使用任何 Cryctography .. :)

      【讨论】:

        【解决方案6】:

        您应该使用类级别的随机变量。如果您在方法级别使用新的 Random 作为本地 ,则与时间相关的种子将重复自身生成相同的随机数序列。

        class Program
        {
         static Random _r = new Random();
         static void Main()
         {
        // use _r variable to generate random number
         }
        }
        

        【讨论】:

        • 在这里使用类级别的变量是无关紧要的,真正的重点是种子的被误解的性质。
        猜你喜欢
        • 2011-11-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-12-10
        • 2013-10-22
        • 2011-05-06
        相关资源
        最近更新 更多