srand函数与rand函数有什么关联?

19

我知道rand()函数如果不改变种子数,每次运行都会生成相同的数字。这就是srand()函数的用处所在。由于时间始终在变化,因此我知道应该将time(null)参数传递给srand。我的问题是关于下面来自教程网站的代码。

int main()
{
    int i, n=5;
    time_t t;

    /* Intializes random number generator */
    srand((unsigned) time(&t));

    /* Print 5 random numbers from 0 to 50 */
    for( i = 0 ; i < n ; i++ ) {
        printf("%d\n", rand() % 50);
    }

    return(0);
}

我没有看到srand的链接。

((unsigned) time(&t)); 

并且 rand.

printf("%d\n", rand() % 50);

rand和srand之间有什么联系?我的意思或期望是,我假设rand()会从srand()获取一些参数,以便它知道每次生成不同的数字。我假设它看起来像rand(srand(time(null));

对我来说,这就像初始化一个变量而不使用它。srand被初始化了,但我没有看到它被使用。

rand是否生成不同的数字,因为在rand之前先调用srand?


在命令行中,您可以通过输入“man 3 rand”和“man 3 srand”来查看这些函数的文档。 - tlehman
4个回答

24

随机数种子是一个全局的静态变量。 randsrand 都可以访问它。


16

srand() 设置种子,用于由 rand 生成“随机”数字(用引号因为它们通常是伪随机的)。如果在第一次调用 rand 之前不调用 srand,就好像你调用了 srand(1) 来将种子设置为一样。

很多代码使用当前时间作为种子,以便使每个程序运行使用不同的随机数序列,但你总是可以在调试期间将其更改为类似 srand(42) 的内容,以实现可重复性。而对于 time() 的调用实际上并不需要一个变量来存储时间,你可以只传递 NULL:

srand (time (NULL));
整个过程可以在一个文件中实现,类似于以下内容,在标准中给出了示例(ISO C99 7.20.2.2 srand函数)。
// RAND_MAX assumed to be 32767.
static unsigned long int next = 1;
void srand(unsigned int seed) { next = seed; }
int rand(void) {
    next = next * 1103515245 + 12345;
    return (unsigned int)(next/65536) % 32768;
}

next是位于文件顶部的静态变量意味着它对文件外的所有内容都是不可见的,但对文件内的一切都是可见的(有点像是局部全局变量)。这就是srand()rand()之间的通信方式。


我认为OP所问的更像是这两个函数的实现。 - WiSaGaN
这里有一个问题 - rand() 函数内的大数值是如何确定的?背后的逻辑是什么? - Gopi

5
你没有看到链接是因为(幸运的是!)设计rand()的人决定将其保留为实现细节,就像您无法看到stdio中FILE内部的内容一样。缺点是,他们决定将该状态设置为全局(但隐藏)变量,而不是生成器的参数。
与已弃用的rand_r()相比:状态是一个无符号整数(假定>=32位),这意味着即使禁止使用任何状态大于它的更好的生成器,只是因为没有足够的空间来存储它!
相反,通过隐藏内部状态,人们可以自由选择任何最好的算法(速度,周期等),并在后台使用它,只要您保证调用未经初始化的rand与使用seed==1调用srand相同。
Paxdiablo向您展示了C标准中的示例;例如,请参见 http://en.wikipedia.org/wiki/Multiply-with-carry ,其中使用了不同的生成器,您可以将其隐藏在rand / srand后面。
仅为了额外-extra清晰:如果rand_r 被正确设计,则会有一种不透明类型,例如rand_t (可以是整数,结构,数组等),您将将其传递给rand_r 和某些假想的srand_r ,如下所示
rand_t state;
srand_r(&state, 1);
n = rand_r(&state);

rand函数与此完全相同,只是它只有一个“state”变量。

我同意你的所有观点。但我认为OP只是想知道rand如何知道种子是什么,如果srand不返回你传递给rand作为参数的东西。即使我们不(不应该!)知道状态有多少位或生成随机数的确切算法,需要状态,其生命周期超过函数调用,并且可以访问两个函数是作为种子的随机数生成器的必然结果 - 没有抽象将不需要静态变量。 - sqykly

0

rand 可以给你一个伪随机数序列。

这个数字是由一个算法生成的,每次调用它都会返回一系列看似不相关的数字。该算法使用种子来生成序列,应使用函数 srand 初始化为某个独特的值。

srand 在每次调用时将指针设置到列表中的某个位置。如果您不在每次尝试时调用它或给它一个固定的种子,它将给您相同的序列。因此,许多人建议将当前秒作为种子。但是,如果您尝试在同一秒内两次运行代码,它将给您相同的序列。

对于在调用 srand 时使用的每个不同种子值,可以期望伪随机数生成器在后续调用 rand 时生成不同的结果序列 有关进一步解释


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接