【发布时间】:2020-04-02 06:42:53
【问题描述】:
我有机会看到一些有趣的代码,它要么被用作愚人节玩笑(更新于 4 月 1 日公开),要么只是一个错误,因为有人不了解如何使用 RNG。
问题与作为 .NET/C# 一部分的 Random 类有关,但可能其他 RNG 的工作方式相同。
我找到的代码的简化版本,去掉所有不必要的细节后,看起来像这样:
for ( int i = startI; i < stopI; ++i ) {
int newValue = new Random( i ).Next( 0, 3 ); // new RNG with seed i generates a single value from 3 options: 0, 1 and 2
// rest of code
}
我确实在 LINQPad 中对该代码进行了简单的测试,以查看我在程序中观察到的是否只是我的“运气”,或者这是否真的是 RNG 以这种方式使用的方式。代码如下:
int lastChoice = -1;
int streakLength = -1;
for ( int i = 0; i < 100000000; ++i ) {
int newChoice = new Random( i ).Next( 0, 3 );
if ( newChoice == lastChoice ) {
streakLength++;
( i + ";" + lastChoice + ";" + streakLength ).Dump();
} else {
lastChoice = newChoice;
streakLength = 1;
}
}
"The End".Dump();
(Dump() 方法只是将值打印到屏幕上)
运行这个“脚本”的结果只是“The End”,仅此而已。这意味着,在生成随机值的 100M 周期中,当只有 3 个作为选项时,它没有一次能够生成相同的连续值。
所以回到标题中的我的问题 - 是否在每次(整数)随机数生成之后将 RNG 的种子(特别是 .NET/C# 的 Random 类,但也欢迎一般答案)增加一个,以确保不会重复会出现连续值吗?或者这只是纯粹的运气?
【问题讨论】:
-
更好的解决方案以及 Random 类的使用方式不是每次需要随机数时都创建一个新实例,而只是实例化一次并重用它。每次调用 Next 时,它的内部种子都会改变,以便后续调用 Next 将返回另一个数字。
-
@ckuri 这不是我应该如何使用它的问题,因为那不是我的代码,我没有维护它。我只对
Random(或其他RNG)的内部结构感兴趣,这样使用它是否不会给我提供连续重复的值,因为这是我出人意料地观察到的。该代码的实际“目标”(除非这是我提到的一个笑话),是在某个时候给你 4 个连续重复的值,而我什至无法并排看到两个相同的数字。 -
Random 类的内部结构是,如果您不提供种子,它将使用当前时间作为种子。因此,在一个紧密的循环中,它会变得如此之快,以至于时钟不会改变,并且您将获得相同的种子和序列,如示例 1 所示。如果您提供的种子不是这种情况。 IIRC 该类使用 Mersenne Twister 算法,该算法的构建方式可以最大限度地减少不同种子的相同序列的机会。我认为有些种子会产生相同的序列,但是我不知道是否有连续的种子也适用。
-
我不明白这个问题的重点。我得到了基本前提。但是,只有大约 40 亿个可能的种子值。为什么不让程序运行更长的时间(即比你已经至少运行一次的时间长 40 倍),然后你就会确定 PRNG 的一个特定实现会做什么?作为编程练习,并行化测试;只有 4 个内核,运行它的时间只需 10 倍(分区几乎完全独立……您只需要跟踪每个内核的第一个和最后一个结果,并将它们与相邻的结果进行比较分区)。
-
如果由于某种原因你真的不想要一个简单的经验答案,你可以在这里看到自己的代码:referencesource.microsoft.com/#mscorlib/system/…(不,没有一般的答案......每个 PRNG会有自己的特点)
标签: c# random random-seed