为什么drand48()和朋友已经过时了?

Dút*_*has 9 c random posix design-rationale obsolete

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

(我花了一些时间在网上搜索这个问题,而我能找到的这个问题的唯一另一个例子是在分布偏差的背景下并且没有得到答复.)

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

尽管如此,我仍然没有找到"过时"地位的理由.

Kei*_*son 9

我的系统上的手册页(来自Linux手册页项目说:

这些函数被SVID 3声明为废弃,它声明 rand(3)应该使用它.

SVID 3于1989年出版.

SVID 4(链接是一个720页的PDF),发表于1995年,文档drand48,erand48,lrand48,nrand48,mrand48,jrand48,srand48,seed48,和lcong48和,像POSIX,也不说他们是过时的.

POSIX,截至2013年,没有说它们已经过时,过时或被弃用.

我还没有找到SVID 3的副本,所以我不知道它为什么会宣布这些功能已经过时,但显然这个决定后来被重新考虑了.手册页中的语句似乎是过时的信息.我不担心.

至于你应该使用哪个函数,C标准rand()函数是最便携的(除非你从源代码重新编译一个不同的函数).一些rand()实现质量差,低阶位以非常规则的模式重复; 其他人稍微好一些.

如果你不需要高质量的伪随机数,你也可以使用rand()(通过调用srand()合理的值来播种,例如,srand(time(NULL)).

如果您确实需要高质量的伪随机数,很可能是没有这些功能是不够好,我会建议不要使用其中的任何密码学,例如.您可以使用/dev/urandom或者/dev/random如果您的系统支持它.我听说过关于Mersenne Twister的好消息,但我缺乏进一步评论的专业知识.

(顺便说一句,如果您在谷歌搜索SVID,请注意Svið).

  • Mersenne Twister 是一个出色的 PRNG,但它不适合加密目的。(它的状态是可观察的,更重要的是,在大约 600 多次迭代之后是可预测的,这并不是很多。)`/dev/urandom` 是 *nixen 上 TRNG 的_正确_选择。至于 `rand()`,我个人认为将它仅仅作为一个_最小_ PRNG(一个_玩具_)包含进来是一个错误,因为现在我们必须忍受它的普遍存在。再次感谢您的精彩回答! (2认同)
  • 这是我的第2000个答案. (2认同)

Die*_*Epp 6

关于标准的说明:

  • rand()是C标准的一部分,因此必须提供。其实现未指定,但是在glibc中,它使用与相同的算法random()。来自man 3 rand

    的版本rand()srand()Linux的C库中使用相同的随机数发生器random(3)srandom(3),...

  • drand48()是POSIX标准的一部分。它的算法似乎已指定,必须使用具有以下公式的48位线性同余生成器(根据man 3 drand48):

       Xn+1 = (aXn + c) mod m, where n >= 0
    
    Run Code Online (Sandbox Code Playgroud)
  • random()是POSIX标准的一部分。根据man 3 random,它使用31个状态字和一个未指定的算法:

    random()函数使用非线性加法反馈随机数生成器,该生成器使用大小为31个长整数的默认表来返回从0到RAND_MAX范围内的连续伪随机数。该随机数生成器的周期非常大,大约为16 *((2 ^ 31)-1)。

因此,POSIX具有这三个随机数生成器。最好的是random()or rand(),它们在glibc中相同(但在其他系统上可能不相同)。该drand48()发生器是一个非常简单的类型(线性同余)与状态的相对少量的(48位),所以它应该避免。这里讨论的随机数生成器都不一定适合于例如蒙特卡洛模拟,但drand48()可能比rand()或差很多random()

我应该使用哪一个?

我总是会避免,drand48()因为它是一个很小的线性同余生成器,具有很小的状态,并且仅在POSIX系统上可用。在POSIX系统上,random()通常可用,并且更好。

我通常会避免,rand()因为在许多系统上,它的生成器很差,通常是线性同余生成器,甚至小于drand48(),并且在某些系统上其最低有效位是循环的。如果您不需要良好的随机数,那rand()很好。

random()如果我需要随机数,但我不太在意它们是如何生成的,则可以在任何POSIX系统上使用。

您始终可以使用自己的随机数生成器:如果您想要一个好的便携式便携式随机数生成器,这是您唯一的选择。过去,尽管较小的发电机似乎很流行,但Mersenne Twister在过去一直是一个受欢迎的选择。