兰德()的GCC实现

voase2hg  于 2024-01-08  发布在  其他
关注(0)|答案(4)|浏览(117)

我花了几个小时才找到gcc中使用的兰德()函数的实现.如果有人能向我推荐包含它的实现的文件或实现的网站,我将不胜感激。
顺便问一下,哪个目录(如果有关系的话,我使用Ubuntu)包含gcc编译器的c标准库实现?

mo49yndu

mo49yndu1#

rand包含对函数__random的调用,该函数主要是调用random_r. c中的另一个名为__random_r的函数。
请注意,上面的函数名是指向glibc源代码库2.28版本的超链接。
glibc随机库支持两种生成器:简单的linear congruential和更复杂的linear feedback shift register。可以构造任何一种的示例,但是当您调用rand时使用的默认全局生成器使用线性反馈移位寄存器生成器(参见unsafe_state.rand_type的定义)。

b09cbbtk

b09cbbtk2#

您将在GNU GLIBC项目中找到GCC使用的C库实现。
你可以下载它的源代码,你应该会找到rand()的实现。带有函数定义的源代码通常不会安装在Linux发行版上。只有我猜你已经知道的头文件通常存储在/usr/include目录中。
如果您熟悉GIT源代码管理,您可以:

$ git clone git://sourceware.org/git/glibc.git

字符串
获取GLIBC源代码。

ruoxqz4g

ruoxqz4g3#

这些文件可以通过FTP获得。我发现stdlib中使用的rand()还有更多,来自[glibc][2]。来自2.32 version(glibc-2.32.tar.gz)得自herestdlib文件夹包含一个random.c文件,该文件解释了使用简单的线性同余算法。该文件夹还包含rand.crand_r.c可以显示更多的源代码。stdlib.h包含在同一个文件夹中,将显示用于宏的值,如RAND_MAX
/* 一个改进的随机数生成包。除了标准的rand()/srand()接口,这个包还有一个特殊的状态信息接口。initstate()例程被调用时带有一个种子,一个字节数组,以及传入的字节数;然后将该数组初始化为包含用于随机数生成的信息和那么多的状态信息。状态信息量的良好大小是32,64、128和256字节。可以通过调用setstate()函数来切换状态,该函数使用的数组与initstate()初始化的数组相同。默认情况下,包以128字节的状态运行
信息,并产生更好的随机数比线性
同馀生成器。如果状态信息量小于32字节,则使用简单的线性同馀R.N.G.。在内部,状态信息被视为长数组;数组的第零个元素是所使用的R.N.G.类型(小整数);数组的其余部分是R.N. G的状态信息。因此,32字节的状态信息将给予7个长的状态信息,这将允许七次多项式。(注意:状态的第零个字
信息中还存储了其他一些信息;随机数生成技术是一种线性反馈移位寄存器方法,采用三项(因为那样求和的项较少)。在这种方法中,状态表中所有数字的最低有效位将充当线性反馈移位寄存器,并且将具有周期2 ^deg- 1(其中deg是所使用的多项式的次数,假设多项式是不可约的和本原的)。高阶位将具有更长的周期,因为它们的值也受到较低位的伪随机进位的影响。
发生器的总周期约为deg*(2deg - 1);因此,状态信息量的加倍对
发生器的周期。注意:当移位寄存器的周期是主要因素时,deg*(2
deg - 1)是仅适用于大deg的近似值。当deg等于7时,周期实际上比此公式预测的7*(2**7 - 1)长得多。*/

okxuctiv

okxuctiv4#

git clone git://sourceware.org/git/glibc.git,我打开了random.c文件。原来,该实现在随机生成周围使用了锁,因此在热路径中的多线程环境中使用此实现是不正确的。

/* 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.  */

long int
__random (void)
{
  int32_t retval;

  __libc_lock_lock (lock);

  (void) __random_r (&unsafe_state, &retval);

  __libc_lock_unlock (lock);

  return retval;
}

weak_alias (__random, random)

字符串
相反,您可以创建生成器的thread_local示例来缓解瓶颈:
在C++中:

thread_local std::mt19937 generator(42 /* seed (can be e.g. time)*/);

void thread_safe_rand(int n) {
  std::uniform_int_distribution<int> distribution(0, n-1);
  return distribution();
}

相关问题