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

时间:2014-08-12 16:26:50

标签: c random posix obsolete design-rationale

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

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

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

尽管如此,我仍然没有找到过时"过时的理由。状态。

2 个答案:

答案 0 :(得分:8)

我系统上的手册页(来自Linux man-pages project说:

  

这些函数被SVID 3声明为废弃   应该使用rand(3)代替。

SVID 3于1989年出版。

SVID 4(链接到720页PDF),1995年出版,文档drand48erand48lrand48nrand48,{ {1}},mrand48jrand48srand48seed48和POSIX一样,没有提及它们已经过时。

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

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

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

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

如果你确实需要高质量的伪随机数,那么这些函数的 none 可能已经足够好了,我建议不要使用它们中的任何一个进行加密, 例如。如果您的系统支持,您可以使用srand(time(NULL))/dev/urandom。我已经听说过有关Mersenne Twister的好消息,但我缺乏进一步评论的专业知识。

(顺便说一句,如果您在Google上搜索SVID,请注意Svið)。

答案 1 :(得分:4)

关于标准的说明:

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

      

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

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

       Xn+1 = (aXn + c) mod m, where n >= 0
    
  • random()是POSIX标准的一部分。根据{{​​3}}:

    ,它使用31个州的单词和未指定的算法
      

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

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

我应该使用哪一个?

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

我通常会避免使用rand(),因为在许多系统上它是一个很差的生成器,通常是一个甚至小于drand48()的线性同余生成器,并且它在某些系统上的最低有效位是周期性的。如果你不需要好的随机数,那么rand()就可以了。

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

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