12

毕竟,它们似乎优于标准的 libc rand()。我错过了什么吗?

(我花了一些时间在网上搜索这个问题,我能找到的这个问题的唯一其他实例是在分布偏差的背景下,并且没有得到答案。)

rand() 和 drand48() 的手册页似乎也不一致。第一个推荐第二个,第二个声明它已经过时,应该使用第一个。(不过,公平地说,许多了解 PRNG 背后数学的人对这些函数的手册页有疑问,因为它们措辞不佳,在某些情况下是错误的。)

尽管如此,我仍然找不到“过时”状态的理由。

4

2 回答 2

14

更新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ð)。

于 2014-08-13T00:51:37.970 回答
6

关于标准的说明:

  • 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 过去一直是一个受欢迎的选择,尽管如今小型发电机似乎很受欢迎。

于 2014-08-12T16:34:20.613 回答