【问题标题】:implementation of the random number generator in C/C++ [duplicate]C/C++中随机数生成器的实现[重复]
【发布时间】:2014-06-03 00:40:40
【问题描述】:

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

如果我理解正确,对“srand(seed)”的调用会以某种方式初始化“rand()”可访问的隐藏变量(种子),这反过来将函数指向预先生成的序列,例如为example this one。对“rand()”的每次连续调用都会推进序列(显然在 C++ 中还有其他推进方式),这也表明使用内部隐藏指针或计数器来跟踪推进。

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

  1. 这里有人可以解释一下这些参数是如何定义的吗?根据标准,它们定义的行为应该是什么,或者它们的行为是否是实现定义的?

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

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

【问题讨论】:

  • srand() 和 rand() 的示例实现可以在 C 标准中找到;请参阅N1570,第 7.22.2 节。这只是一个示例,但它应该给你一个想法。同一部分定义了这两个功能的要求。
  • 感谢 Kevin Thompson 的参考。
  • 我认为我的问题与被称为重复的问题大不相同。该问题并未询问 rand() 和 srand() 的内部变量的范围和可访问性。这个问题是关于可重复性的。如果我问的信息在那篇文章中可用,我就不会提出新问题

标签: c++ c random


【解决方案1】:

rand 的要求是:

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

该标准没有定义任何方法来恢复内部状态以进行重新播种或其他任何操作。

对于实现什么 PRNG 没有要求,因此每个实现都可以有自己的,尽管Linear Congrueantial Generators 是最受欢迎的。

在这个 dilbert strip 中提供了一个符合要求(尽管可以说是无用的)实现:

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

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

为了完整起见,标准引号:

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++ 包括 rand、srand 和 RAND_MAX,没有通过引用 C 标准进行更改。
不过,有一些 C++ 库函数/类被明确记录为使用 C 随机数生成器。

【讨论】:

  • 感谢 Dedupicator 的详细解答。我之所以询问 C 和 C++ 之间的差异,是因为 this link 的“兼容性”下的注释。感谢您清除它。
【解决方案2】:

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

C99 标准对rand 和srand 的实际实现细节非常简单。它只是声明srand 的参数被“用作seed 用于后续调用rand 时返回的新伪随机数序列。”

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

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

C 标准给出了一个可能实现 rand 和 srand 的示例,它们表现出这种行为:

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; 
} 

【讨论】:

  • 一个重要的注意事项是,由于next 是static,因此无法从该翻译单元外部访问或修改它。这可能已经为你编译好了,所以没有(理智的)方法可以与之交互。
  • 感谢 jwodder 和 Mooing Duck。这无疑消除了我的困惑,也阐明了为什么某些实现是线程不安全的,因为它们可能在内部使用静态变量。
猜你喜欢
  • 1970-01-01
  • 2018-06-25
  • 2014-06-10
  • 1970-01-01
  • 1970-01-01
  • 2012-12-17
  • 2012-11-28
  • 2012-08-10
相关资源
最近更新 更多