C语言 rand()函数总是用相同的种子产生相同的结果吗?



我正在尝试在C中实现一组编码和解码隐写功能,其中我使用rand()将数据随机分散到数组中。

我使用rand计算随机索引,如下所示:

unsigned int getRandIndex(int size) {
return ((unsigned)(rand() * 8)) % size;
}

我像这样播种:

unsigned long seed = time(NULL);
srand(seed);

我将种子和我的数据一起作为包含校验和和长度的报头的一部分。

我遇到的问题是,在解码时,当我用从数据中解码的种子再次播种rand函数时,rand()倾向于产生最轻微的变化,如:

Index at encode:                  | Index at decode:
---------------------------------------------------------------------
.
.
.
At:                        142568 | At:                        142568
At:                        155560 | At:                        155552
--                                  --
At:                        168184 | At:                        168184
.
.
.

弄乱了我的解码数据。

这是rand()函数的限制吗?我100%确定种子被正确地逐位解码,因为我已经验证了这一点。

C 2018 7.22.2.2 2说:

srand函数使用该参数作为一个新的伪随机数序列的种子,这些伪随机数序列将在随后调用rand时返回。如果再用相同的种子值调用srand,则重复伪随机数序列。

这并没有明确地说序列在程序的不同执行中是相同的,但我认为这是可以理解的。但是,它不能扩展到不同的C实现,包括那些由于链接到不同版本的C标准库而产生的实现。

OpenBSD的rand实现忽略对srand的所有调用,而是提供自动种子,加密强随机数,就像您使用arc4random一样;这被记录为对C标准的故意偏离。这表明,即使您的文件总是在生成它们的同一台计算机上解码,也不能保证rand会做您想要的。

如果您需要可重复的伪随机数序列,您应该做工业级统计软件所做的事情,即发布您自己的PRNG并记录您选择的算法。(参见r的?Random帮助页面)

此外,由于这是一个隐写应用程序,您需要使用密码学强的PRNG(也称为流密码);仅仅是统计上很强的prng,比如梅森龙卷风,还不够好。

No。为了再现性,使用rand(没有精确指定,并且固有地使用全局状态)是很糟糕的,原因有很多:

  1. 你可能会使用不同的编译器/系统,它可能会使用不同的RNG,

  2. 你可能会使用相同的编译器,但更新到一个新版本,使用不同的RNG,

  3. 你可能会使用相同的编译器,相同的版本,但有一个更新的libc,使用不同的RNG,

  4. 您使用相同的编译器和库版本,但有任何其他不确定的RNG调用顺序,包括但不限于:

    a)其他随机性来源,

    b)用户输入, c)从运行到运行的并发重新排序,或者

    d)在您使用的任何库中执行上述任何操作。

最新更新