【问题标题】:Seeding a pseudo-random number generator in C#在 C# 中播种伪随机数生成器
【发布时间】:2010-10-30 22:31:24
【问题描述】:

我需要一个 C# 的 Random 类实例的种子,并且我了解到大多数人为此使用当前时间的刻度计数器。但这是一个 64 位的值,种子需要是一个 32 位的值。现在我认为返回intGetHashCode() 方法应该为其对象提供合理分布的值,这可以用来避免仅使用滴答计数的低32 位。但是,我找不到有关 Int64 数据类型的 GetHashCode() 的任何信息。

所以,我知道这无关紧要,但下面的工作是否会像我想的一样好(我不能试错随机性),或者它可能与使用 (int)DateTime.Now.Ticks 作为种子?或者它甚至可能更糟糕?谁能解释一下。

int seed = unchecked(DateTime.Now.Ticks.GetHashCode());
Random r = new Random(seed);

编辑:为什么我需要一个种子而不是让Random() 构造函数来完成工作?我需要将种子发送给对相同随机序列使用相同种子的其他客户端。

【问题讨论】:

  • 你忘记写出你需要种子的非常好的论据
  • 好吧,我现在补充说非常好的论据。 :)

标签: c# random gethashcode


【解决方案1】:

new Random() 已经使用当前时间。相当于new Random(Environment.TickCount)

但这是一个实现细节,可能会在未来的 .net 版本中发生变化

我建议使用 new Random() 并且仅在您想要获得可重现的伪随机值序列时提供固定种子。

因为你需要一个已知的种子,所以就像 MS 一样使用Environment.TickCount。然后将其作为种子传递给其他程序实例。

如果您在短时间内(可能是 16 毫秒)创建多个 Random 实例,则可以将它们播种为相同的值,从而创建相同的伪随机序列。但这很可能不是问题。这个常见的陷阱是由窗口仅每隔几毫秒更新一次当前时间(DateTime.Now/.UtcNow) 和 TickCount(Environment.TickCount) 引起的。确切的时间间隔取决于 Windows 的版本以及正在运行的其他程序。它们不改变的典型间隔是 16 毫秒或 1 毫秒。

【讨论】:

  • +1 提到真正提供自己的种子值的唯一时间是当您想要重现特定的值序列时。按照 Windows Solitaire“游戏编号”选项的思路思考。
  • 我编辑了我的问题。我知道new Random() 构造函数,但我需要种子。
  • @AndrewBarber 或者,如果您在 Random 生成之外迭代方法/块,需要唯一的种子并希望避免由于时间分辨率不足而导致冲突的风险,正如 CodesInChaos 所写的那样。
  • @Alex 我很确定这实际上不是 CodeInChaos 所说的。我引用,“如果你想获得一个可重复的......值序列,只提供一个固定的种子”。你不应该创建这么多 Random 实例。
  • @Alex 我也在想同样的事情 ;) 我确实认为您对此有所了解,但我只是认为我们之间存在一些微小的技术问题或某些东西!可怜的 CodeInChaos 会想知道为什么他的回答会爆炸! ;)
【解决方案2】:

如果您需要使用当前时间以外的其他时间播种它(在这种情况下,您可以使用默认构造函数),您可以使用这个:

Random random = new Random(Guid.NewGuid().GetHashCode());

【讨论】:

  • 那为什么比DateTime.Now.Ticks.GetHashCode() 更有价值?
  • 这样更好,因为它不会遇到DateTime.Now 每隔几毫秒更改一次的问题。使用这种方法,即使快速连续初始化,两个 random 实例也不太可能获得相同的种子。
  • 您确定没有哈希冲突?
  • @CodesInChaos 正是 oɔɯǝɹ 所说的 - 如果您只使用 GUID,可能会更少。 stackoverflow.com/questions/7326593/guid-gethashcode-uniqueness
  • 这种方法会在 gethashcode 碰巧返回 int.minvalue 时随机炸毁,因为随机对种子执行 abs 并且 abs 在 int.minvalue 上炸毁。你需要这样做...... Random random = new Random(Guid.NewGuid().GetHashCode() & int.MaxValue); 确保你只发送正整数。
【解决方案3】:

我有一个类似的问题,从更大的问题列表中随机选择一组问题。但是当我将时间用作种子时,它会给出相同的随机数。

所以这是我的解决方案。

    int TOTALQ = 7;
    int NOOFQ = 5;

    int[] selectedQuestion = new int[TOTALQ];

    int[] askQuestion = new int[NOOFQ];

    /*   Genarae a random number 1 to TOTALQ
     *   - if that number in selectedQuestion array is not o
     *   -     Fill askQuestion array with that number
     *   -     remove that number from selectedQuestion
     *   - if not re-do that - - while - array is not full.    
     */

    for (int i = 0; i < TOTALQ; i++)  // fill the array
        selectedQuestion[i] = 1;

    int question = 0;

    int seed = 1;

    while (question < NOOFQ)
    {       
        DateTime now1 = new DateTime();
        now1 = DateTime.Now;    
        Random rand = new Random(seed+now1.Millisecond);
         int RandomQuestion = rand.Next(1, TOTALQ);

         Response.Write("<br/> seed  " + seed + " Random number " + RandomQuestion );



        if (selectedQuestion[RandomQuestion] != 0)      
        {
            selectedQuestion[RandomQuestion] = 0;  // set that q =0 so not to select           
            askQuestion[question] = selectedQuestion[RandomQuestion];
            Response.Write(".  Question no " + question + " will be question " + RandomQuestion + " from list " );
            question++;
        }

        seed++;         

    }

【讨论】:

    猜你喜欢
    • 2014-03-24
    • 1970-01-01
    • 2010-11-01
    • 2011-02-08
    • 1970-01-01
    • 2012-08-10
    • 1970-01-01
    • 1970-01-01
    • 2010-10-05
    相关资源
    最近更新 更多