第一个随机数总是小于rest

我碰巧注意到,在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()输出似乎随时间线性变化。 只是想知道为什么

我不确定这可以归类为一个错误,但它有一个解释。 我们来看看情况:

  1. 看看rand的实现 。 你会看到这只是一个使用最后生成的值的计算。

  2. 您使用QTime :: currentTime()。msec()进行播种,这本质上是由值0..999的小范围限制的 ,但qsrand接受范围为0..4294967295uintvariables。

通过结合这两个因素,你有一个模式。

出于好奇:尝试使用QTime :: currentTime()。msec()+ 100000000进行播种

现在,第一个值可能会大于第二个大部分时间。

我不会太担心。 这种“模式”似乎只发生在前两个生成的值上。 之后,一切似乎都恢复正常了。

编辑:

为了使事情更清楚,请尝试运行下面的代码。 它会比较前两个生成的值,看看哪一个更小,使用所有可能的毫秒值(范围: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%的时间第一个值会小于第二个。

结论:当使用当前毫秒播种时,您将看到前两个值的模式。 我在这里做了一些testing,模式似乎在第二个值生成后消失。 我的build议是:find一个“好”的值来调用qsrand (在你的程序开始时显然应该只调用一次)。 良好的价值应该跨越整个范围。 看看这个问题的一些想法:

  • build议初始化srand的方法?

另外,看看这个:

  • PCG:一个更好的随机数发生器家族

目前的Qt和C标准运行时间都没有质量随机数发生器,并且您的testing显示。 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所指出的,我们可以应用不同的随机引擎,然后使用不同的分布,但对于我的具体使用,上述工作非常好。

记住,根据less量样本对统计现象做出判断可能会产生误导,我决定进行一个小实验。 我运行下面的代码:

 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); } } } 

基本上打印的第一次生成的次数的百分比小于第二次。 下面你看到这个比例的情节:

在这里输入图像说明

正如你所看到的,在less于50个实际的新种子之后,它实际上接近0.5。

正如评论中所build议的那样,我们可以修改代码以在每次迭代中使用连续的种子,并加速收敛:

 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当然不是最好的伪随机数发生器, 但是它在第一次运行时经常产生一个较小数字的说法似乎没有保证