13

我是编程新手。

我想确切地知道 rand() 做了什么。

搜索只会产生有关其用法的示例。但是没有人解释函数如何生成随机数的每一步。他们将 rand() 视为黑盒。

我想知道 rand() 在做什么;每一步。

是否有资源可以让我准确了解 rand() 的作用? 这都是开源的东西不是吗?如果没有来源,我会满足于拆卸。

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

谢谢你。

4

7 回答 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;
}
于 2013-09-23T22:21:35.843 回答
13

这是 10 秒的谷歌搜索:

...

我打算列出实际的搜索,但看到这显然是一个骗局,我会投票为骗局

于 2013-09-23T22:23:35.697 回答
3

您可以浏览 C 标准的不同实现的源代码。

该问题之前已回答,您可能会在C 的 rand() 使用哪些常用算法?

该答案为 glibc 的 rand() 实现提供了代码

于 2013-09-23T22:20:17.467 回答
2

我想,就是你要找的。它包含随机函数的详细解释,以及理解算法的简单 C 程序。

编辑:

你也应该检查这个。可能的重复。

于 2013-09-23T22:22:49.587 回答
2

好吧,我相信 rand 来自 C 标准库,而不是 C++ 标准库。这两个库都没有一个实现,有几个。

你可以去类似这个页面的地方查看 glibc 的源代码,glibc 是大多数 Linux 发行版上使用的 c 库。对于 glibc,您可以在 stdlib 下的源文件中找到它,rand.c例如random.c.

一个不同的实现,比如 uClibc 可能更容易阅读。在 libc/stdlib 文件夹下尝试。

于 2013-09-23T22:24:07.853 回答
1

最简单的相当好的伪随机数生成器是线性同余生成器 (LCG)。这些是公式的迭代,例如

X_{n+1} = (a * X_n  +  c) modulo m

选择常数 a、c 和 m 以给出不可预测的序列。X_0 是随机种子值。存在许多其他算法,但这可能足以让您继续前进。

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

于 2013-09-23T22:21:39.893 回答
0

如果我错了,请纠正我,但是虽然这个答案指向了部分实现,但我发现还有更多要rand()使用的stdlib内容,即来自[glibc][2]. 从这里获得的2.32 版本中,该文件夹包含一个文件,该文件解释了使用简单的线性同余算法。该文件夹也有并且可以显示更多的源代码。包含在同一文件夹中将显示用于宏的值,例如.stdlibrandom.crand.crand_r.cstdlib.hRAND_MAX

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

于 2021-01-08T03:53:21.783 回答