昨天我在my first answer写了Programming Puzzles & Code Golf。问题是:
给定输入字符串
S
,打印S
后跟非空分隔符 通过以下方式:
第1步:
S
有1/2
的机会被打印,1/2
机会终止该机会。第2步:
S
有2/3
的机会被打印,1/3
机会终止该计划。第3步:
S
有3/4
的机会被打印,1/4
机会终止该机会。...
步骤
n
:S
有n/(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
实例的时间过于接近时,这两个不同的序列会有多大差异?
答案 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中做了很好的可视化:
位图的每一行代表五个带有该种子的第一个生成的数字(不保留生成的顺序):
如您所见,数字是从不同但相关的序列中选择的。正如postmessage
上的MSDN所说,“所选数字......出于实际目的而具有足够的随机性。”