在C / C ++中实现随机数生成器

时间:2014-06-03 00:40:40

标签: c++ c random

我对C中随机数生成器的实现感到有些困惑,这也明显不同于C ++中的随机数生成器

如果我理解正确,调用'srand(seed)'会以某种方式初始化一个隐藏变量(种子),该变量可以被'rand()'访问,而后者又将该函数指向预先生成的序列,如为example this one。每次连续调用'rand()'都会使序列前进(显然还有其他方法可以在C ++中前进),这也建议使用内部隐藏指针或计数器来跟踪进度。

我发现很多关于伪随机数生成算法如何工作以及函数rand()和srand()的文档的讨论,但是却无法找到有关这些隐藏参数及其行为的信息,除according to this source之外,它们不是线程安全的。

  1. 请问这里的任何人请详细说明这些参数是如何定义的,根据标准定义的行为应该是什么,或者他们的行为是否是实现定义的?

  2. 它们是否应该是调用rand()和srand()的函数/方法的本地?如果是这样,有没有办法将它们传达给另一个函数/方法?

  3. 如果您的答案特定于C或C ++,请非常友好地指出它。任何信息将不胜感激。请记住,这个问题不是关于predictability of data generated by rand() and srand(),而是关于内部变量的要求,状态和功能以及它们的可访问性和范围。

2 个答案:

答案 0 :(得分:6)

rand的要求是:

  • 生成伪随机数。
  • 范围是0到RAND_MAX(最小值32767)。
  • srand()设置的种子确定返回的伪随机数序列。
  • 它不需要是线程安全的,甚至不是可重入的,状态可以存储在静态变量中。

标准没有定义任何方法来恢复重播或其他任何内部状态。

对PRNG的实施没有要求,因此每个实现都有自己的实现,但Linear Congrueantial Generators是最受欢迎的。

这个dilbert条带中提供了一个符合(虽然可以说是无用的)实现:

http://dilbert.com/strips/comic/2001-10-25/

对于那些喜欢XKCD的人(它是任何C或C ++库的完美插件; - )):

enter image description here

为完整起见,标准引用:

  

7.22.2.1 rand 功能

     

rand 函数计算0到0范围内的伪随机整数序列   的 RAND_MAX 即可。
   rand 函数不需要避免与其他伪随机调用的数据竞争   序列生成函数。实现应该表现得好像没有库函数   调用 rand 函数。
  [...]
   RAND_MAX 宏的值至少应为32767。

     

7.22.2.2 srand 功能

     

srand 函数使用该参数作为新随机伪随机序列的种子   后续调用 rand 返回的数字。如果随后调用 srand   在相同的种子值下,应重复伪随机数的序列。如果 rand 是   在对 srand 进行任何调用之前调用,应生成相同的序列   当第一次调用 srand 时,种子值为1   不需要 srand 函数来避免与其他伪随机调用的数据竞争   序列生成函数。实现应该表现得好像没有库函数   调用 srand 函数。

C ++包含randsrandRAND_MAX,不会因C标准的引用而改变。
有一些C ++库函数/类被明确记录,但使用C随机数生成器。

答案 1 :(得分:3)

以下答案适用于C;特别是1999年的标准。

C99标准对rand&的实际实施细节非常清楚。 srand。它只是声明srand的参数“作为seed用于后续调用rand返回的新的伪随机数序列。”

在实践中,它通常的工作方式是:

  • C库定义了一个randsrand用来跟踪PRNG状态的整数变量。
  • srand将状态变量设置为提供的值。
  • rand获取状态变量的值并对其执行一些数学魔术以产生两个新的整数:一个是它返回的伪随机数,另一个是状态变量的新值,从而影响对rand的下一次调用(假设在此之前未调用srand)。

C标准提供了展示此行为的randsrand的可能实现示例:

static unsigned long int next = 1; 

int rand(void) // RAND_MAX assumed to be 32767 
{ 
    next = next * 1103515245 + 12345; 
    return (unsigned int)(next/65536) % 32768; 
} 

void srand(unsigned int seed) 
{ 
    next = seed; 
}