如何获取rand()函数的源代码(C++)?

15

我是新手程序员。

我想确切知道rand()函数的作用。

搜索只能得到关于它用法的例子,但没有一个解释函数如何生成随机数的每一步骤,它们把rand()函数视为黑盒子。

我想知道rand()在做什么,每一步都是怎样的。

有没有资源可以让我看到rand()的具体操作?这不都是开源的吗?如果没有源代码,我也可以接受反汇编结果。

我知道它返回一个随机数,但它是如何生成这个数字的呢?我想看到每一步。

谢谢。


5
你关心哪个系统?可能会有几乎与环境一样多的实现。 - Carl Norum
你的编译器可能有运行时库源代码可用。实现可能可以在那里找到。 - Retired Ninja
2
rand使用伪随机生成器,因此阅读PRNG背后的理论将比任何源代码更具启发性。 - Uku Loskit
这篇论文是一篇经典之作,不难理解,并且涵盖了基础知识,尽管在现代标准下它有些原始。 (但rand()也是如此。) - Hot Licks
7个回答

17

这里是当前的glibc实现

/* Return a random integer between 0 and RAND_MAX.  */
int
rand (void)
{
  return (int) __random ();
}

虽然这并没有太大帮助,但是__random最终会调用__random_r函数:

/* If we are using the trivial TYPE_0 R.N.G., just do the old linear
   congruential bit.  Otherwise, we do our fancy trinomial stuff, which is the
   same in all the other cases due to all the global variables that have been
   set up.  The basic operation is to add the number at the rear pointer into
   the one at the front pointer.  Then both pointers are advanced to the next
   location cyclically in the table.  The value returned is the sum generated,
   reduced to 31 bits by throwing away the "least random" low bit.
   Note: The code takes advantage of the fact that both the front and
   rear pointers can't wrap on the same call by not testing the rear
   pointer if the front one has wrapped.  Returns a 31-bit random number.  */

int
__random_r (buf, result)
     struct random_data *buf;
     int32_t *result;
{
  int32_t *state;

  if (buf == NULL || result == NULL)
    goto fail;

  state = buf->state;

  if (buf->rand_type == TYPE_0)
    {
      int32_t val = state[0];
      val = ((state[0] * 1103515245) + 12345) & 0x7fffffff;
      state[0] = val;
      *result = val;
    }
  else
    {
      int32_t *fptr = buf->fptr;
      int32_t *rptr = buf->rptr;
      int32_t *end_ptr = buf->end_ptr;
      int32_t val;

      val = *fptr += *rptr;
      /* Chucking least random bit.  */
      *result = (val >> 1) & 0x7fffffff;
      ++fptr;
      if (fptr >= end_ptr)
    {
      fptr = state;
      ++rptr;
    }
      else
    {
      ++rptr;
      if (rptr >= end_ptr)
        rptr = state;
    }
      buf->fptr = fptr;
      buf->rptr = rptr;
    }
  return 0;

 fail:
  __set_errno (EINVAL);
  return -1;
}

15

2
好的。我对编程非常新手(约3天!),所以我不知道该搜索什么。我在这里找到了需要学习的实现:http://bioen.okstate.edu/Home/prashm%20-%20keep/prashant/VS.NET%20setup%20files/PROGRAM%20FILES/MICROSOFT%20VISUAL%20STUDIO%20.NET/VC7/CRT/SRC/RAND.C - BBedit
@user2071506 哦,我直接谷歌搜索了“GNU libc rand”。结果SO的链接也出现在前12个搜索结果里。可惜没有其他来源的链接。 :/ - sehe
@sehe GNU libc rand 很难。从标题中复制的 rand() (C++) 源代码也给我带来了不错的结果。 - Bartek Banachewicz

4

2
最简单且表现良好的伪随机数生成器是线性同余生成器(LCGs)。它们是通过一个公式的迭代产生的,例如:
X_{n+1} = (a * X_n  +  c) modulo m

常数a、c和m被选择为给出不可预测的序列。X_0是随机种子值。还有许多其他算法,但这可能足以让您开始。

真正好的伪随机数生成器更加复杂,例如Mersenne Twister


能解释一下为什么是-1吗? - Kevin A. Naudé

2
我猜,这里可能是你要找的。它包含了随机函数的详细解释以及简单的C程序来理解算法。
编辑:
你也应该查看这里。这可能是一个重复的问题。

2

我认为rand函数来自于C标准库,而不是C++标准库。C和C++标准库都有多种实现。

你可以访问此页面查看大多数Linux发行版中使用的c库glibc的源代码。在glibc中,你可以在stdlib这样的源文件中找到它,例如rand.crandom.c

另一种实现,例如uClibc,可能更容易阅读。在此处查看libc/stdlib文件夹下的内容。


0

如果我错了,请纠正我,尽管this answer指向了实现的一部分,但我发现在stdlib中使用的rand()还有更多内容,这些内容来自于[glibc][2]。从2.32版本中获取的herestdlib文件夹包含一个random.c文件,其中解释了使用简单的线性同余算法。该文件夹还有rand.crand_r.c,可以显示更多源代码。在同一文件夹中包含的stdlib.h将向您展示用于宏的值,例如RAND_MAX

/* 一个改进的随机数生成包。除了标准的 rand() / srand() 接口外,该包还具有一种特殊的状态信息接口。initstate()例程被调用,带有种子、字节数组和传递的字节数量计数;然后,此数组被初始化为包含使用该数量的状态信息进行随机数生成的信息。良好的状态信息量大小为32、64、128和256字节。可以通过使用与initstate()初始化的相同数组调用setstate()函数来切换状态。默认情况下,该包以128字节的状态信息运行,并生成比线性同余生成器更好的随机数。如果状态信息量小于32字节,则使用简单的线性同余R.N.G。在内部,状态信息被视为longs数组;数组的第零个元素是正在使用的R.N.G.类型(小整数);其余数组是R.N.G.的状态信息。因此,32个字节的状态信息将提供7个长的状态信息,这将允许度数为7的多项式。(注意:状态信息的零字也存储有其他信息,请参见setstate)。随机数生成技术是一种线性反馈移位寄存器方法,采用三项式(因为这样需要求和的项较少)。在这种方法中,状态表中所有数字的最低有效位将作为线性反馈移位寄存器,并且具有2^deg - 1的周期(其中deg是多项式的度数,假设该多项式是不可约的和原始的)。高阶位的周期将更长,因为它们的值也受较低位的伪随机进位影响。发生器的总周期大约为deg *(2 * deg-1);因此,将状态信息量加倍对发生器的周期产生了巨大的影响。(注意:deg*(2 * deg-1)仅适用于大deg时,移位寄存器的周期是主要因素。当deg等于七时,周期实际上比此公式预测的7 *(2 ** 7-1)还要长。) */

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