rand() 函数是否总是使用相同的种子产生相同的结果?
Will the rand() function ALWAYS produce the same result with the same seed?
我正在尝试在 C 中实现一组编码和解码隐写术函数,其中我使用 rand() 将我的数据随机散布在一个数组中。
我使用 rand 来计算随机索引,如下所示:
unsigned int getRandIndex(int size) {
return ((unsigned)(rand() * 8)) % size;
}
我这样播种兰特:
unsigned long seed = time(NULL);
srand(seed);
我将种子连同我的数据作为包含校验和和长度的 header 的一部分。
我遇到的问题是,在解码时,当我再次使用从数据解码的种子为 rand 函数播种时,rand() 往往会产生像这样的最轻微的变化:
Index at encode: | Index at decode:
---------------------------------------------------------------------
.
.
.
At: 142568 | At: 142568
At: 155560 | At: 155552
-- --
At: 168184 | At: 168184
.
.
.
弄乱我的解码数据。
这是 rand() 函数的限制吗? 我 100% 确定种子被正确解码 bit-for-bit 因为我已经验证了这一点。
没有。由于多种原因,使用 rand
(未完全指定并且本质上使用全局状态)的可重复性很糟糕:
你可能会使用不同的compiler/system,这可能会使用不同的RNG,
您可能使用相同的编译器,但更新到使用不同 RNG 的新版本,
您可能使用相同的编译器,相同的版本,但更新后的 libc
,使用不同的 RNG,
您使用相同的编译器和库版本,但有任何其他非确定性的RNG调用顺序,包括但不限于:
a) 其他一些随机性来源,
b) 用户输入,
c) 从 运行 到 运行 或
的并发重新排序
d) 您使用的任何库中的任何上述内容。
C 2018 7.22.2.2 2 说:
The srand
function uses the argument as a seed for a new sequence of pseudo-random numbers to be returned by subsequent calls to rand
. If srand
is then called with the same seed value, the sequence of pseudo-random numbers shall be repeated.
这并没有明确表示程序的不同执行顺序是相同的,但我认为这是理解的。但是,它不会扩展到不同的 C 实现,包括那些链接到不同版本的 C 标准库的实现。
OpenBSD's implementation of rand
忽略对 srand
的所有调用,而是提供自动播种的加密强随机数,就像您使用 arc4random
一样;这被记录为故意偏离 C 标准。这表明,即使您的文件总是在生成它们的同一台计算机上解码,也不能保证 rand
会执行您想要的操作。
如果您需要可重复的伪随机数序列,您应该执行工业级统计软件所做的工作,即发布您自己的 PRNG 并记录您选择的算法。 (例如参见 [=16=]。)
此外,由于这是一个隐写术应用程序,您需要使用加密强度高 PRNG(也称为流密码) ;仅仅像 Mersenne Twister 这样统计上强大的 PRNG 还不够好。
我正在尝试在 C 中实现一组编码和解码隐写术函数,其中我使用 rand() 将我的数据随机散布在一个数组中。
我使用 rand 来计算随机索引,如下所示:
unsigned int getRandIndex(int size) {
return ((unsigned)(rand() * 8)) % size;
}
我这样播种兰特:
unsigned long seed = time(NULL);
srand(seed);
我将种子连同我的数据作为包含校验和和长度的 header 的一部分。
我遇到的问题是,在解码时,当我再次使用从数据解码的种子为 rand 函数播种时,rand() 往往会产生像这样的最轻微的变化:
Index at encode: | Index at decode:
---------------------------------------------------------------------
.
.
.
At: 142568 | At: 142568
At: 155560 | At: 155552
-- --
At: 168184 | At: 168184
.
.
.
弄乱我的解码数据。
这是 rand() 函数的限制吗? 我 100% 确定种子被正确解码 bit-for-bit 因为我已经验证了这一点。
没有。由于多种原因,使用 rand
(未完全指定并且本质上使用全局状态)的可重复性很糟糕:
你可能会使用不同的compiler/system,这可能会使用不同的RNG,
您可能使用相同的编译器,但更新到使用不同 RNG 的新版本,
您可能使用相同的编译器,相同的版本,但更新后的
libc
,使用不同的 RNG,您使用相同的编译器和库版本,但有任何其他非确定性的RNG调用顺序,包括但不限于:
a) 其他一些随机性来源,
b) 用户输入,
c) 从 运行 到 运行 或
的并发重新排序d) 您使用的任何库中的任何上述内容。
C 2018 7.22.2.2 2 说:
The
srand
function uses the argument as a seed for a new sequence of pseudo-random numbers to be returned by subsequent calls torand
. Ifsrand
is then called with the same seed value, the sequence of pseudo-random numbers shall be repeated.
这并没有明确表示程序的不同执行顺序是相同的,但我认为这是理解的。但是,它不会扩展到不同的 C 实现,包括那些链接到不同版本的 C 标准库的实现。
OpenBSD's implementation of rand
忽略对 srand
的所有调用,而是提供自动播种的加密强随机数,就像您使用 arc4random
一样;这被记录为故意偏离 C 标准。这表明,即使您的文件总是在生成它们的同一台计算机上解码,也不能保证 rand
会执行您想要的操作。
如果您需要可重复的伪随机数序列,您应该执行工业级统计软件所做的工作,即发布您自己的 PRNG 并记录您选择的算法。 (例如参见 [=16=]。)
此外,由于这是一个隐写术应用程序,您需要使用加密强度高 PRNG(也称为流密码) ;仅仅像 Mersenne Twister 这样统计上强大的 PRNG 还不够好。