我碰巧注意到在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;
Run Code Online (Sandbox Code Playgroud)
输出:
qt1: 7109361
qt2: 1375429742
std1: 871649082
std2: 1820164987
Run Code Online (Sandbox Code Playgroud)
这是因为播种错误还是错误?此外,当qrand()输出强烈变化时,第一个rand()输出似乎随时间线性变化.只是想知道原因.
Raf*_*iro 15
我不确定这可能被归类为错误,但它有一个解释.我们来看看情况:
看看兰德的实现.您将看到它只是使用上一个生成的值进行计算.
您正在使用QTime :: currentTime().msec()播种,它本质上由小范围的值0..999限制,但qsrand接受一个uint变量,范围为0..4294967295.
通过结合这两个因素,你就有了一个模式.
出于好奇:尝试用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;
Run Code Online (Sandbox Code Playgroud)
它将打印94.8,这意味着94.8%的时间第一个值将小于第二个值.
结论:当使用当前毫秒种子时,您将看到前两个值的模式.我在这里做了一些测试,在生成第二个值后,模式似乎消失了.我的建议:找到一个"好"的值来调用qsrand(显然应该只在程序开始时调用一次).一个好的值应该跨越uint类的整个范围.看看这个问题的另一个问题:
另外,看看这个:
Ale*_*r V 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);
Run Code Online (Sandbox Code Playgroud)
有很好的视频涵盖了这个主题.正如评论者user2357112所指出的,我们可以应用不同的随机引擎然后应用不同的发行版,但是对于我的具体用途,上面的工作非常好.
请记住,基于少量样本对统计现象做出判断可能会产生误导,我决定进行一项小型实验.我运行以下代码:
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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
它基本上打印了第一个生成的数字小于第二个的百分比.您可以在下面看到该比率的图表:

正如你所看到的,实际新种子实际上不到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;
}
}
Run Code Online (Sandbox Code Playgroud)
这给了我们:

它也非常接近0.5.
虽然rand肯定不是最好的伪随机数生成器,但它在第一次运行期间经常生成较小数字的说法似乎并不合理.