两个不同的种子产生相同的“随机”序列
Posted
技术标签:
【中文标题】两个不同的种子产生相同的“随机”序列【英文标题】:Two different seeds producing the same 'random' sequence 【发布时间】:2012-11-02 02:20:53 【问题描述】:也许对此有一个非常合乎逻辑的解释,但我似乎无法理解为什么种子 0
和 2,147,483,647
使用 .NET 的 Random Class (System) 产生相同的“随机”序列。
快速代码示例:
var random1 = new Random(0);
var random2 = new Random(1);
var random3 = new Random(int.MaxValue); //2,147,483,647
var buffer1 = new byte[8];
var buffer2 = new byte[8];
var buffer3 = new byte[8];
random1.NextBytes(buffer1);
random2.NextBytes(buffer2);
random3.NextBytes(buffer3);
for (int i = 0; i < 8; i++)
Console.WriteLine("0\t\t1\t\t2", buffer1[i], buffer2[i], buffer3[i]);
输出:
26 70 26
12 208 12
70 134 76
111 130 111
93 64 93
117 151 115
228 228 228
216 163 216
如您所见,第一个和第三个序列是相同的。有人可以向我解释一下吗?
编辑:显然,正如 alro 所指出的,这些序列并不相同。但它们非常相似。
【问题讨论】:
System.Random
在很多方面都被设计破坏了。这是其中之一。
+1 非常有趣的观察!
@RuudLenders 我明白了。这很奇怪。显然这个功能并不完美。 :(微软,你怎么能!
没有人会指出他的结果不是一样的吗?第三个和第六个数字不同。
@alro 没关系,因为他们所说的功能是生成一个预先计算好的种子数组。然后使用它来生成每个样本。更多种子在该数组中是相同的,并且您将获得更多随机数序列(在这种情况下,数组仅相差一项)但是......两个序列不应该重复相同的数字模式......
【参考方案1】:
好吧,原因将与 Random 类用于从种子中派生伪随机序列的任何派生函数有关。因此,真正的答案是数学的(超出了我的能力范围)。
确实 - 我不相信有任何保证两个不同的种子一定会产生不同的序列。
编辑好的 - 我将按照 bitbonk 所做的工作 - 但请解释为什么:
public Random(int Seed)
int num = (Seed == -2147483648) ? 2147483647 : Math.Abs(Seed);
int num2 = 161803398 - num;
this.SeedArray[55] = num2;
int num3 = 1;
for (int i = 1; i < 55; i++)
int num4 = 21 * i % 55;
this.SeedArray[num4] = num3;
num3 = num2 - num3;
if (num3 < 0)
num3 += 2147483647;
num2 = this.SeedArray[num4];
for (int j = 1; j < 5; j++)
for (int k = 1; k < 56; k++)
this.SeedArray[k] -= this.SeedArray[1 + (k + 30) % 55];
if (this.SeedArray[k] < 0)
this.SeedArray[k] += 2147483647;
this.inext = 0;
this.inextp = 21;
Seed = 1;
我们实际上不需要深入代码来了解原因 - 从上到下阅读代码,这些是当种子为 0
和当种子时,上述代码将存储的值是2147483647
:
int num = (Seed == -2147483648) ? 2147483647 : Math.Abs(Seed);
=> num is 0 and 2147483647
int num2 = 161803398 - num;
=> num2 is 161803398 and -1985680249
this.SeedArray[55] = num2;
=> this.SeedArray is as above in both cases
int num3 = 1;
for (int i = 1; i < 55; i++)
int num4 = 21 * i % 55
this.SeedArray[num4] = num3;
=> num4 is 21, SeedArray[21] is 1
num3 = num2 - num3
=> num3 is 161803397 and -1985680250
if(num3 < 0)
num3 += 2147483647
=> num3 is 161803397 and 161803397
在第一个循环之后,算法已经针对两个种子值收敛。
编辑
正如在问题中所指出的那样 - 序列并不相同 - 但它们显然非常相似 - 在这里我们可以看到这种相似性的原因。
【讨论】:
感谢您的详细信息!值得注意的是 0,int.Max,int.Min 会产生相同的种子,正如该线程所证明的那样。我想知道这个实现是否以及有多少其他这样的共同种子?如果还有更多,那将为一篇文章打下一个很好的基础:) +1 干得好! @quetzalcoatl 好吧,我认为 System.Random 实现甚至不是一个像样的随机数生成器,而是一个随时可用的、非常快速的例程,每次您甚至不必考虑它的优点时都可以使用。这就是为什么(即使在框架内)有这么多不同的实现。 @Adriano 但是文档暗示了更多。 msdn.microsoft.com/en-us/library/ctssatww.aspx 如果您的应用程序需要不同的随机数序列,请使用不同的种子值重复调用此构造函数。 @ReacherGilt:我认为说他不应该得到这么好的答案是不公平的。他问了一个很好的问题,大概是什么对他来说是一段黑匣子代码。我不知道那本书,作为一个不使用 C 编程的人可能不会想拿起它。您找到答案的方式是对的,但它仍然是一个很好的问题,有一个很好的答案。 @ReacherGilt:我不知道我是否看到了一个好的答案。当我看到它时,它只是复制和粘贴上面构造函数的代码,没有任何实际答案。但我并不是说不可能有任何好的答案。我只是不确定是否公平地说它超过了应得的。如果是这样,那将意味着一个糟糕的问题,而评分(在撰写本文时为 16 分,没有下降)表明情况远非如此。以上是关于两个不同的种子产生相同的“随机”序列的主要内容,如果未能解决你的问题,请参考以下文章