毕竟,它们似乎优于标准的 libc rand()。我错过了什么吗?
(我花了一些时间在网上搜索这个问题,我能找到的这个问题的唯一其他实例是在分布偏差的背景下,并且没有得到答案。)
rand() 和 drand48() 的手册页似乎也不一致。第一个推荐第二个,第二个声明它已经过时,应该使用第一个。(不过,公平地说,许多了解 PRNG 背后数学的人对这些函数的手册页有疑问,因为它们措辞不佳,在某些情况下是错误的。)
尽管如此,我仍然找不到“过时”状态的理由。
毕竟,它们似乎优于标准的 libc rand()。我错过了什么吗?
(我花了一些时间在网上搜索这个问题,我能找到的这个问题的唯一其他实例是在分布偏差的背景下,并且没有得到答案。)
rand() 和 drand48() 的手册页似乎也不一致。第一个推荐第二个,第二个声明它已经过时,应该使用第一个。(不过,公平地说,许多了解 PRNG 背后数学的人对这些函数的手册页有疑问,因为它们措辞不佳,在某些情况下是错误的。)
尽管如此,我仍然找不到“过时”状态的理由。
更新:drand48
和朋友并没有过时,手册页不再说他们是。显然,更改是为了响应这个答案(这有点酷)。
一个包含 Linux 手册页的 git repo 在这里:
https://git.kernel.org/pub/scm/docs/man-pages/man-pages.git
相关的日志条目是:
commit 3db3ecf0ff358ab86ead91d767b8ef502bffe26b
Author: Michael Kerrisk <mtk.manpages@gmail.com>
Date: 2014-09-13 20:08:10 -0700
drand48.3: Remove crufty text about SVID 3 marking drand48() obsolete
See http://bugs.debian.org/758293
drand48() is in current POSIX. It's unclear why SVID 3 would
have marked it obsolete, but that's crufty information that
only serves to pointlessly worry people.
Reported-by: Lorenzo Beretta <lory.fulgi@infinito.it>
Signed-off-by: Michael Kerrisk <mtk.manpages@gmail.com>
另请参阅此错误报告:https ://bugs.debian.org/cgi-bin/bugreport.cgi?bug=758293 ,它触发了更改。
我的原始答案如下。
我系统上的手册页(来自Linux 手册页项目)说:
SVID 3 声明这些函数已过时,
rand(3)
应改为使用这些函数。
SVID 3 于 1989 年出版。
SVID 4(链接指向一个 720 页的 PDF)于 1995 年出版,文档drand48
, erand48
, lrand48
, nrand48
, mrand48
, jrand48
, srand48
, seed48
, andlcong48
和 POSIX 一样,没有说明它们已经过时。
截至 2013 年,POSIX没有说明它们已过时、过时或弃用。
我还没有找到 SVID 3 的副本,所以我不知道为什么它会宣布这些功能已过时,但显然后来重新考虑了这个决定。手册页中的声明似乎是过时的信息。我不会担心的。
至于你应该使用哪个函数,C 标准rand()
函数是最可移植的(除非你从源代码重新编译一个不同的函数)。一些rand()
实现质量很差,低位以非常规则的模式重复;其他的稍微好一点。
如果您不需要高质量的伪随机数,您不妨使用(通过使用合理值rand()
调用来播种,例如.srand()
srand(time(NULL))
如果您确实需要高质量的伪随机数,很可能这些功能都不够好,例如,我建议不要将它们中的任何一个用于密码学。您可以使用/dev/urandom
或者/dev/random
如果您的系统支持它。我听说过有关Mersenne Twister的好消息,但我缺乏进一步评论的专业知识。
(顺便说一句,如果您在 Google 上搜索 SVID,请注意Svið)。
关于标准的说明:
rand()
是 C 标准的一部分,因此必须提供。它的实现是未指定的,但在 glibc 中,它使用与random()
. 来自man 3 rand:
rand()
Linux C 库中的and版本使用与andsrand()
相同的随机数生成器,...random(3)
srandom(3)
drand48()
是 POSIX 标准的一部分。它的算法似乎是指定的,它必须使用具有以下公式的 48 位线性同余生成器(根据man 3 drand48):
Xn+1 = (aXn + c) mod m, where n >= 0
random()
是 POSIX 标准的一部分。根据man 3 random的说法,它使用 31 个状态字和未指定的算法:
random() 函数使用非线性加性反馈随机数生成器,该生成器采用大小为 31 个长整数的默认表来返回 0 到 RAND_MAX 范围内的连续伪随机数。这个随机数生成器的周期非常大,大约为 16 * ((2^31) - 1)。
所以,POSIX 有这三个随机数生成器。最好的是random()
or rand()
,这在 glibc 中是相同的(但在其他系统上可能不一样)。生成器drand48()
是一种非常简单的类型(线性同余),状态量相对较少(48 位),因此应避免使用。这里讨论的随机数生成器都不一定适用于例如蒙特卡罗模拟,但drand48()
可能比rand()
or差得多random()
。
我总是会避免drand48()
,因为它是一个很小的线性同余生成器,状态很小,而且它只在 POSIX 系统上可用。在 POSIX 系统上,random()
通常可用,并且更好。
我通常会避免rand()
,因为在许多系统上它是一个糟糕的生成器,通常是一个甚至小于 的线性同余生成器drand48()
,并且它在某些系统上的最低有效位是循环的。如果您不需要好的随机数,那rand()
很好。
random()
如果我需要随机数但不太关心它们是如何生成的,我会在任何 POSIX 系统上使用。
您始终可以使用自己的随机数生成器:如果您想要一个好的、便携的随机数生成器,这是您唯一的选择。Mersenne Twister 过去一直是一个受欢迎的选择,尽管如今小型发电机似乎很受欢迎。