stdlib中的random()函数分布是什么?

6

这篇 man 手册声称 C 标准库中的 random 函数“返回介于0和 RAND_MAX 之间的值。”

不幸的是,它没有说明这个随机函数的分布情况。经验证,我们可以测量它是均匀的,但没有文档说明,我不能确定在应用程序中使用它时它永远不会改变。

这个分布是否有任何文档记录呢?


4
制服。您可以轻松通过一小段代码进行验证。 - Mitch Wheat
2
@MitchWheat,那是经验性的。有没有任何标准保证它始终是一致的? - merlin2011
3
ISO C的随机数函数被称为rand()random()是BSD的随机数函数:https://www.gnu.org/software/libc/manual/html_node/Pseudo_002dRandom-Numbers.html#Pseudo_002dRandom-Numbers - kfx
3
如果你承诺生成一个范围内的随机数,那么人们会认为它是均匀分布的,否则你会失去一些随机性(熵的损失)。根据我的经验,只有在随机数的分布不是均匀分布时,你才会提到它的分布情况。 - Greg Schmit
6
“random”函数不是C11规范的一部分,而“rand”函数是。因此,我认为说“C标准库中的随机函数”是不正确的。 - user3386109
显示剩余3条评论
2个回答

9
C标准和POSIX规范均未定义random()rand()的分布。我查阅的一些系统的man页面似乎也没有定义这个问题。我认为,在遇到的计算机上,可以非常安全地假设random()rand()会产生随机数,这些随机数(大约)累积到均匀分布,但如果您不确定,可以进行经验测试。一般而言,如果承诺生成一个范围内的随机数,则默认情况下(当数量趋近于无穷大时),它们应该累积到均匀分布,否则您将失去一些随机性(熵的损失)。根据我的经验,仅当随机数生成器的分布与均匀分布不同(例如,他们可能告诉您某些特定的伪随机数生成器将按照正态分布生成随机数)时,才会提及随机数生成器的分布。

编辑(POSIX)

在验证我的假设时,我发现了POSIX函数族,这些函数被定义为生成均匀分布的随机数:

NAME

drand48, erand48, jrand48, lcong48, lrand48, mrand48, nrand48, seed48, srand48 - generate uniformly distributed pseudo-random numbers

SYNOPSIS

#include <stdlib.h>

double drand48(void);
double erand48(unsigned short xsubi[3]);
long jrand48(unsigned short xsubi[3]);
void lcong48(unsigned short param[7]);
long lrand48(void);
long mrand48(void);
long nrand48(unsigned short xsubi[3]);
unsigned short *seed48(unsigned short seed16v[3]);
void srand48(long seedval);

FreeBSD的drand48手册指出它们不具有加密安全性,并推荐使用arc4random()进行加密应用。arc4random()来自BSD,但已被移植到其他系统--它被定义为产生均匀分布。


4
random(void)函数不是C标准的一部分。但是,(@nwellnhof!)它是POSIX标准的一部分。 它在glibc文档POSIX中有记录。然而,没有任何发行版被这两个文本保证。 glibc:

long int random(void)

初步:|MT-Safe|AS-Unsafe锁|AC-Unsafe锁|请参阅第1.2.2.1节[POSIX安全概念],第2页。

此函数返回序列中的下一个伪随机数。返回值范围从0到2147483647。

NB: 暂时将此函数定义为返回 int32_t 值,以指示返回值始终包含32位,即使 long int 更宽。标准要求不同。用户必须始终注意32位限制。

POSIX:

random()函数使用非线性加法反馈随机数生成器,采用默认状态数组大小为31个长整型数,以返回在0到2^31-1范围内的连续伪随机数。该随机数生成器的周期约为16 x (2^31-1)。状态数组的大小决定了随机数生成器的周期。增加状态数组大小可以增加周期。
使用256字节的状态信息,随机数生成器的周期大于2^69。
与rand()类似,默认情况下,random()产生一系列可以通过将种子设置为1调用srandom()来重复的数字序列。
srandom()函数使用seed的值初始化当前状态数组。
initstate()和setstate()函数处理重新启动和更改随机数生成器。initstate()函数允许初始化一个状态数组,由state参数指向,以备将来使用。size参数指定状态数组的字节数,用于决定要使用什么类型的随机数生成器;状态数组越大,数字越随机。状态信息量的值为8、32、64、128和256字节。大于8字节的值会被四舍五入到最接近这些值之一。对于大于或等于8,或小于32的值,random()使用简单的线性同余随机数生成器。种子参数指定随机数序列的起始点,并提供在相同点重新开始的功能。initstate()函数返回先前状态信息数组的指针。
如果没有调用initstate(),那么random()的行为就像调用了seed=1和size=128的initstate()一样。
如果使用8 <= size < 32调用initstate(),则random()使用简单的线性同余随机数生成器。
一旦状态被初始化,setstate()允许在状态数组之间切换。由state参数定义的数组用于进一步的随机数生成,直到调用initstate()或再次调用setstate()。setstate()函数返回先前状态数组的指针。
然而,如果您正在使用GLIBC,并且想要一个伪随机数函数,它保证按照标准产生在其范围内均匀分布的随机数,那么您可以使用SVID random functionslrand48和相关函数:
来自第330页:

函数lrand48()nrand48()返回非负长整型,在区间[0,2^31)上均匀分布。

这些函数也被POSIX定义

1
rand()不是random()。 - Mitch Wheat
2
@kfx,这个问题不含糊不清。我没有任何地方提到rand()函数。 - merlin2011
2
实际上,“random”不是C标准的一部分。它似乎是glibc的一部分。而且很可能不会成为一个标准。 - OmnipotentEntity
2
random是由POSIX标准化的。 - nwellnhof
还有一件事,如果你真的想要一个被文档保证均匀分布的伪随机数生成器,如果这在某种程度上实际上是一个阻碍,那么 SVID 随机函数就可以了。请参见我的编辑。 - OmnipotentEntity
显示剩余3条评论

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