新的Random()取决于时间多少钱?

时间:2017-06-13 08:31:51

标签: c# random

昨天我在my first answer写了Programming Puzzles & Code Golf。问题是:

  

给定输入字符串S,打印S后跟非空分隔符   通过以下方式:

     
      
  • 第1步:S1/2的机会被打印,1/2机会终止该机会。

  •   
  • 第2步:S2/3的机会被打印,1/3机会终止该计划。

  •   
  • 第3步:S3/4的机会被打印,1/4机会终止该机会。

  •   
  • ...

  •   
  • 步骤nSn/(n+1)的机会被打印,并有1/(n+1)机会终止该程序。

  •   

所以我去写了这段代码(ungolfed):

Action<string> g = s =>
{
    var r = new Random();
    for (var i = 2; r.Next(i++) > 0;)
        Console.Write(s + " ");
};

这段代码工作正常,但有人说我可以保存几个字节来创建r变量内联,如下所示:

Action<string> g = s =>
{
    for (var i = 2; new Random().Next(i++) > 0;)
        Console.Write(s + " ");
};

我试过,但是当我执行代码时,它总是有两种可能性之一:

  • 程序在打印任何内容之前停止(第一次调用Next()返回0)或
  • 程序永不停止(对Next()的调用永远不会返回0)。

当我将代码恢复为原始提案时,程序会按照OP的预期更随机地停止。

我知道new Random()构造函数取决于时间,但是多少?如果我添加Sleep()调用,代码行为开始看起来非常随机(但不多,返回的字符串仍然比初始代码返回的字符串长):

Action<string> g = s =>
{
    for (var i = 2; new Random().Next(i++) > 0; Thread.Sleep(1))
        Console.Write(s + " ");
};

如果我将睡眠时间增加到10毫秒,那么现在代码的行为与原始代码完全相同。

那为什么呢? Random课程取决于时间多少钱?调用空构造函数时Random类对数字生成器的确定程度如何?

注意:我知道创建单个Random对象是最佳做法,我只想知道what the MSDN says以上的内容:

  

默认种子值是从系统时钟导出的,具有有限的分辨率。

Random类默认构造函数用作种子的“有限分辨率”是什么?我们应该将两个Random对象的构造分开以获得不同的序列多长时间?在创建Random实例的时间过于接近时,这两个不同的序列会有多大差异?

1 个答案:

答案 0 :(得分:0)

  

Random类默认构造函数用作种子的“有限分辨率”是什么?

It uses Environment.TickCount which has a resolution of one millisecond

  

我们应该将两个Random对象的构造分开多长时间以获得不同的序列?

根据上一节,至少一毫秒 - 或者每次手动将另一个种子提供给构造函数(或者,重用同一个生成器?)

  

当创建Random实例的时间太近时,这两个不同的序列会有多大差异?

Matt Moss在他的Random Headaches from System.Random blog post中做了很好的可视化:

位图的每一行代表五个带有该种子的第一个生成的数字(不保留生成的顺序):

Random() sets with adjacent seeds, image by Matt Moss

如您所见,数字是从不同但相关的序列中选择的。正如postmessage上的MSDN所说,“所选数字......出于实际目的而具有足够的随机性。”