【问题标题】:What‘s the difference between srand(1) and srand(0)srand(1) 和 srand(0) 有什么区别
【发布时间】:2011-12-24 08:59:03
【问题描述】:

我刚刚发现srand(1) 将 C(++) 的 PRNG 重置为调用srand 之前的状态(如reference 中所定义)的艰难方式。 但是,种子 0 似乎也这样做,或者在任何调用 srand 之前的状态似乎使用种子 0。 这两个调用有什么区别,或者它们做同样事情的原因是什么?

例如这个代码(execute on Ideone

#include <stdio.h>
#include <stdlib.h>

int main() {
    for (int seed = 0; seed < 4; seed++ ) {
        printf( "Seed %d:", seed);
        srand( seed );
        for(int i = 0; i < 5; i++ )
            printf( "    %10d", rand() );
        printf( "\n");
    }
    return 0;
}

返回

Seed 0:    1804289383     846930886    1681692777    1714636915    1957747793
Seed 1:    1804289383     846930886    1681692777    1714636915    1957747793
Seed 2:    1505335290    1738766719     190686788     260874575     747983061
Seed 3:    1205554746     483147985     844158168     953350440     612121425

【问题讨论】:

  • 非常有趣的问题。据我所知, srand 没有任何“神奇”值,但 rand() 只是简单地初始化为种子 1,因此除非告诉不同的东西,否则从该种子开始。这隐含地意味着如果您调用 srand(1),您将“重置为原始状态”。但是,您发布的输出表明它确实“神奇地重置”为您之前设置的种子 0,而不是 1(顺便说一句。我的实现这样做)。

标签: c++ c random srand


【解决方案1】:

之所以指定 1,是因为如果种子设置为零,一些随机数生成器会卡在零。例如移位寄存器和乘法同余类型,即r(n+1) = (A * r(n))mod M

许多 C 实现使用线性同余r(n+1) = (A * r(n) + B) mod M, B 0 不会卡住。

【讨论】:

  • 这与问题有什么关系?
【解决方案2】:

glibc 是如何做到的:

around line 181 of glibc/stdlib/random_r.c,内部函数__srandom_r

  /* We must make sure the seed is not 0.  Take arbitrarily 1 in this case.  */
  if (seed == 0)
    seed = 1;

但这就是 glibc 的工作方式。这取决于 C 标准库的实现。

【讨论】:

    【解决方案3】:

    如果种子设置为 1,则生成器将重新初始化为其初始值,并生成与调用 rand 或 srand 之前相同的值。取自 srand 参考

    【讨论】:

      【解决方案4】:

      srand() 函数将参数用作新伪随机数序列的种子,这些伪随机数将由后续调用 rand() 返回。如果随后使用相同的种子值调用 srand(),则应重复伪随机数序列。如果在调用 srand() 之前调用了 rand(),则应生成与第一次调用 srand() 时相同的序列,种子值为 1。

      也许有用:http://pubs.opengroup.org/onlinepubs/009695399/functions/rand.html

      【讨论】:

        【解决方案5】:

        阅读手册页时,它们都声明“如果未提供种子值,则 rand() 函数将自动以值 1 为种子。”这可能就是您链接到的参考页面声明使用 1 播种会重置状态的原因。

        对于同时使用 0 和 1 的种子,同样的结果很可能取决于实现,不应指望在所有平台上都会发生。

        【讨论】:

          【解决方案6】:

          这可能是一个实现细节。该标准要求随机种子 1 是特殊的,并且您的特定随机生成器算法的内部寄存器可能是零初始化的,因此导致种子(0)和种子(1)的随机序列相同。我什至打赌你的 srand() 实现的第一行看起来像:

          if ( seed == 1 ) seed = 0;
          

          强制符合标准的行为。

          一般来说,rand() 和 srand() 的随机数生成器不需要为不同的种子给出不同的序列,但对同一个种子给出相同的序列。所以,不要依赖不同的种子生成不同的随机序列,你应该没问题。如果没有,欢迎体验特定于实现的乐趣。

          【讨论】:

          • 实际上,代码更像if (seed == 0) seed = 1;,因为rand() 的GNU 实现所使用的算法不适用于零种子。
          【解决方案7】:

          C 和 C++ 标准都没有详细说明 rand()srand() 的实现细节。细节几乎完全由实施者决定。 C 标准要求:

          如果随后使用相同的种子值调用 srand,则应重复伪随机数序列。如果在调用 srand 之前调用了 rand,则应生成与第一次调用 srand 时相同的序列,种子值为 1。

          但它不包含不同种子必须产生不同序列的任何要求。显然,在您的系统上,零和一的种子具有相同的效果。我猜这是为了提供与某些期望srand(0) 将 PRNG 重置为其初始状态的软件的向后兼容性。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2022-12-22
            • 1970-01-01
            • 2019-09-04
            • 2011-06-11
            • 1970-01-01
            • 1970-01-01
            • 2010-10-15
            • 2021-12-20
            相关资源
            最近更新 更多