我碰巧注意到在C ++中,使用std rand()方法调用的第一个随机数大部分时间都明显小于第二个。关于Qt实现,第一个几乎总是小几个。
qsrand(QTime::currentTime().msec());
qDebug() << "qt1: " << qrand();
qDebug() << "qt2: " << qrand();
srand((unsigned int) time(0));
std::cout << "std1: " << rand() << std::endl;
std::cout << "std2: " << rand() << std::endl;
输出:
qt1: 7109361
qt2: 1375429742
std1: 871649082
std2: 1820164987
这是因为播种错误还是错误? 此外,当qrand()输出强烈变化时,第一个rand()输出似乎随时间线性变化。只是想知道为什么。
答案 0 :(得分:15)
我不确定是否可归类为错误,但它有一个解释。让我们来看看情况:
请看rand's implementation。您将看到它只是使用上一个生成的值进行计算。
您正在使用 QTime :: currentTime()。msec()播种,其本质上是由小范围的值 0..999 <限定的/ em>,但 qsrand 接受 0..4294967295 范围内的 uint 变量。
通过结合这两个因素,你就有了一种模式。
出于好奇:尝试播种 QTime :: currentTime()。msec()+ 100000000
现在,第一个值可能会大于第二个值。
我不会太担心。这种&#34;模式&#34;似乎只发生在前两个生成的值上。在那之后,一切似乎都恢复正常。
为了更清楚,请尝试运行以下代码。它将前两个生成的值进行比较,以查看哪一个较小,使用所有可能的毫秒值(范围:0..999)作为种子:
int totalCalls, leftIsSmaller = 0;
for (totalCalls = 0; totalCalls < 1000; totalCalls++)
{
qsrand(totalCalls);
if (qrand() < qrand())
leftIsSmaller++;
}
qDebug() << (100.0 * leftIsSmaller) / totalCalls;
它将打印94.8,这意味着94.8%的时间第一个值将小于第二个值。
结论:当使用当前毫秒播种时,您将看到前两个值的模式。我在这里做了一些测试,在生成第二个值后,模式似乎消失了。我的建议是:找到一个好的&#34;调用 qsrand 的值(显然应该只在程序开头调用一次)。一个好的值应该跨越 uint 类的整个范围。看看这个问题的另一个问题:
另外,看看这个:
答案 1 :(得分:12)
目前的Qt和C标准运行时都没有质量随机发生器,您的测试显示。 Qt似乎使用C运行时(这很容易检查,但为什么)。如果您的项目中有C ++ 11可用,那么使用更好更方便的方法:
#include <random>
#include <chrono>
auto seed = std::chrono::system_clock::now().time_since_epoch().count();
std::default_random_engine generator(seed);
std::uniform_int_distribution<uint> distribution;
uint randomUint = distribution(generator);
有很好的video涵盖了这个主题。正如评论者user2357112所述,我们可以应用不同的随机引擎,然后应用不同的发行版,但对于我的具体用途,上面的工作非常好。
答案 2 :(得分:8)
请记住,基于少量样本对统计现象做出判断可能会产生误导,我决定进行一项小型实验。我运行以下代码:
int main()
{
int i = 0;
int j = 0;
while (i < RAND_MAX)
{
srand(time(NULL));
int r1 = rand();
int r2 = rand();
if (r1 < r2)
++j;
++i;
if (i%10000 == 0) {
printf("%g\n", (float)j / (float)i);
}
}
}
基本上打印了第一个生成的数字小于第二个的百分比。您可以在下面看到该比率的图表:
并且正如您所看到的,在实际新种子少于50之后它实际上接近0.5。
正如评论中所建议的,我们可以修改代码以在每次迭代时使用连续种子并加速收敛:
int main()
{
int i = 0;
int j = 0;
int t = time(NULL);
while (i < RAND_MAX)
{
srand(t);
int r1 = rand();
int r2 = rand();
if (r1 < r2)
++j;
++i;
if (i%10000 == 0) {
printf("%g\n", (float)j / (float)i);
}
++t;
}
}
这给了我们:
也非常接近0.5。
虽然rand
肯定不是最好的伪随机数生成器,但声称它在第一次运行期间经常生成较小的数字似乎并不合理。