为什么rand()在使用1和UINT_MAX进行种子设定时会产生相同的值
Why does rand() produce the same value when seeded with 1 and UINT_MAX?
下面是一些代码:
#include <iostream>
int main() {
srand(1);
std::cout << rand() << "n";
srand(UINT_MAX);
std::cout << rand() << "n";
}
这会产生以下输出:
16807
16807
为什么这两种种子会产生相同的结果?它们在连续的rand()
调用中产生的整个值序列也是相同的。可能值的范围太大,这不可能是纯粹的巧合。是吗
rand()
实现的意外(如果是,我很好奇这可能是什么)- 按设计(如果是,为什么?)
(可能相关:种子10、100、1000、10000和100000分别产生168070、1680700、16807000、168070000和1680700000。)
一个非常简单可用的随机数生成器是Lehmer数生成器。这个RNG可能是最简单的软件实现,它仍然可用,所以它可能具有最多的随机性问题,也最容易分析。
数字16807(又名7的五次方)与Lehmer RNG有关,因为它在1988年被用于最早的实现之一——显然今天仍在使用!
第N个随机数的公式为(使用^
求幂):
R(n) = (seed * (16807 ^ n)) mod (2 ^ 31 - 1)
如果设置种子=1,n=1:
R(1) = 16807 mod (2 ^ 31 - 1) = 16807
如果设置seed=2 ^ 32 - 1
:
R(1) =
(2 ^ 32 - 1) * 16807 ≡ (expressing 2^32 = 2^31 * 2)
((2 ^ 31 - 1) * 2 + 1) * 16807 ≡ (distributive law)
(2 ^ 31 - 1) * 2 * 16807 + 1 * 16807 ≡ (modulo 2^31-1)
16807
这里,随机序列中第一个数的相等性是因为Lehmer RNG中的模数几乎是2的幂(2^31-1
),而您的种子也几乎是2(2^32-1
)的幂。
对于seed=2^31
也会发生同样的情况。
tl;dr:众所周知rand()
有那么糟糕。
实际值由实现定义。我在我的平台上获得以下值:
seed: 1 : 41
seed: 4294967295 : 35
seed: 10 : 71
seed: 100 : 365
seed: 1000 : 3304
seed: 10000 : 32694
对于匆匆忙忙的普通用户来说,CCD_ 9看起来有些随意。它不适合携带其他物品。
实现通常使用低质量的生成器(最常见的是常数不好的线性同余)。
所需的数字范围是0…32767,虽然实现可能,但它们通常不会超过这个范围,因此您可以预期许多种子会产生相同的值。
对于C++modern,请参阅<random>
以获得可靠的选项。
这取决于随机数生成器的实现。请参阅C';s rand()?用于常见的实现。
通常,可能的种子值的空间比UINT_MAX
短得多。可能是1和CCD_ 12被映射到相同的内部种子。
rand()
通常使用线性同余生成器,然后第一个生成的随机数像一样依赖
first_random_number = (seed * const + another_const) % third_constant
在种子上。这就解释了你发现的依赖性。
我看不出有什么好的理由可以将您观察到的不幸关联设计到您正在使用的rand
的实现中。正如您所建议的,这很可能是实现的意外。也就是说,我也认为这是一个巧合,你可以产生与这些输入的相关性。另一个实施可能会有其他一些令人遗憾的投入。
如果是的话,我很好奇那可能是什么
如果您的实现是开源的,那么您可以通过阅读源代码来找到答案。如果它是专有的,你仍然可以在一些文档中找到算法的提及,或者如果你是客户,你可以询问实现者。
如上所述,如果seed设置为1,生成器将重新初始化为其初始值,并产生与任何对rand或srand的调用前相同的值。
还要注意,使用相同种子的两个不同初始化将在后续对rand的调用中生成相同的连续结果
- Ardunio UNO解决了多个重叠的定时器循环
- 如何使用要传递给 mt19937 的可选随机种子参数设计函数
- 从给定种子生成相同的随机数序列C++
- 处理影响跨不同线程共享对象的定时回调的最佳方法是什么?
- 我们能否在stm32f中使用硬件定时器控制两个独立的进程
- Arduino Nano:A4988 使用串行输入时通过定时器进行步进控制不稳定
- 如何使用可选的随机种子参数创建 roll_die() 函数
- 在 Windows/C++ 上使用多进程应用程序的高精度定时操作
- 没有信号处理程序的POSIX定时器的目的是什么?
- 是否可以为boost::random::uniform_int_distribution<>设置确定性种子?
- 使用给定种子生成的随机数序列是否保证在标准版本中相同?
- 在编译时生成某种子类/类型注册表?
- 在定时器回调函数中使用 Sleep() 会导致C++出现问题吗?
- libtorrent是否支持带摘要身份验证的http web种子
- 我应该使用std::seed_seq来种子std::mt19937吗
- 除了 rand() 之外,是否有任何随机生成器库,开发人员可以手动设置种子?
- 随机数生成器的种子和状态有什么区别?
- 如果我在每个平台上使用相同的种子,随机结果会相同吗?
- 如何在Qt中修改QWebsocket定时器
- C++多个实例的随机数生成器组种子中增强