两个不同的种子产生相同的“随机”序列

Posted

技术标签:

【中文标题】两个不同的种子产生相同的“随机”序列【英文标题】:Two different seeds producing the same 'random' sequence 【发布时间】:2012-11-02 02:20:53 【问题描述】:

也许对此有一个非常合乎逻辑的解释,但我似乎无法理解为什么种子 02,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 分,没有下降)表明情况远非如此。

以上是关于两个不同的种子产生相同的“随机”序列的主要内容,如果未能解决你的问题,请参考以下文章

参数变化:固定,但运行的种子不同

函数RAND啥意思

C# Random 生成不重复随机数

Java_常用类09_Random类

rand产生随机数怎样控制在1~52内而且不能重复。1~52必须出现一次。谢谢

java中Random随机种子使用