stdlib的rand()函数是否总是给出相同的序列?

6

我非常喜欢能够重复生成相同的伪随机数据,特别是在调试实验性代码时。通过观察,我会说rand()似乎每次都给出相同的数字序列。

它保证在相同的机器上/不同的机器上/不同的架构上重复执行时会这样吗?

*显然是相同的种子。

6个回答

21

是的,在相同程序环境下可以。根据C标准 §7.20.2.2/2,

srand函数使用参数作为伪随机数新序列的种子,以便在后续调用rand时返回。如果使用相同的种子值调用srand,则将重复伪随机数序列。如果在调用srand之前调用rand,则生成的序列与使用值为1的种子值首次调用srand时相同。

当然,这假设它正在使用相同的实现细节(即同一台机器,在相同执行期间使用相同库)。C标准没有强制规定标准的伪随机数生成算法,因此,如果您使用不同的C标准库运行程序,则可能会得到不同的伪随机数序列。

如果需要具有给定种子的可移植和保证的随机数序列,请参见问题跨平台的一致伪随机数


好的。我同意对于特定的运行时库,序列将是相同的。因此,一旦应用程序构建完成(针对特定的运行时版本),它将始终生成相同的序列。但是,这是否适用于不同版本的运行时(即跨操作系统/架构/运行时版本等)?如果是这样,那就意味着标准定义了rand()算法的确切实现(否则两个独立的操作系统如何确保它们符合)。 - Martin York
3
它不跨越运行时版本 - 如果您动态链接到rand()的实现,可能会在不重新构建任何内容的情况下表现不同。 - JoeG
@Martin:但是这是否适用于不同版本的运行时呢?并不是。实际上,更新是否会改变行为取决于运行时。 - kennytm
谢谢您的回答!微调阶段仅在一台机器上进行(我为完整起见添加了扩展问题)。 - Joe
标准中的语言仅保证在程序执行期间每次使用相同值调用srand()时会得到相同的序列(“如果srand然后被调用…”意味着它发生在同一程序内)。实现可以在程序启动时选择一个“主种子”,这会使算法在每次运行程序时都有所不同,这也是符合规范的。 - caf

2
srand()传递相同的种子会保证在程序单次执行期间生成相同的序列,但通常情况下,如果实现可以选择行为,则没有特定的要求使该选择在后续执行中保持不变。
在每次程序启动时,从一个“主种子”中选择并使用它以不同于程序上次启动的方式扰动伪随机数生成器是符合要求的。如果您希望更多确定性,请在程序中实现具有特定参数的PRNG。

1

不。

C标准规定:

如果使用相同的种子值调用srand,则伪随机数序列将重复。

但是,它并没有说明伪随机数序列实际上是什么-因此在不同的实现中会有所不同。

唯一的保证是,对于给定的实现,rand()将为给定的种子提供相同的数字序列。不能保证在不同的计算机或不同的架构之间序列将相同-几乎肯定不会。


0
如果您在UNIX/Linux环境中,可以在man页面上找到drand48()srand48()的相关信息。如果不是,您可以查看C语言的在线手册。 函数原型可以在/usr/include/stdlib.h中找到。 第一个函数使用线性同余方法,这在模拟中经常使用。
如果您给srand48()提供相同的种子,例如srand48(2),然后将drand48()放在一个for循环中,那么每次生成的序列都将相同。
include stdio.h
include stdlib.h
double drand48();
int main(void){
    int i;
    double rn;
    srand48(2);
    for(i=0; i<10; i++){
        randNum = drand48();
        printf("%.6l\n", randNum);
        return 0;
}

0
如果您需要为实验目的使用完全相同的伪随机数集,您可以使用srand生成一长串随机数并将它们写入文件/数据库。然后,编写一个可移植的“随机数生成器”函数,从该文件中顺序返回值。这样,无论平台、srand实现或种子值如何,都可以确保使用相同的输入数据。

好主意。如果我有这样的需求,我肯定会采取这种方法。我的问题更多是出于好奇而不是需要一个已知序列。 - Joe
或者你可以自己编写一个随机函数? - deceleratedcaviar

0

当切换到不同的机器/运行时/任何其他情况时,您可能会遇到麻烦。还有另一种可能的选择是drand48函数族。这些函数被规范化为在所有机器上使用相同的算法。


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