rand()给出了相同的值

时间:2013-03-31 20:18:05

标签: c++ random

我注意到通过做一个简单的基于控制台的测验应用程序练习。当我使用rand()时,它连续几次给我相同的值。数字范围越小,问题就越大。

例如

for (i=0; i<10; i++) {
    x = rand() % 20 + 1;
    cout << x << ", ";
}

会给我1, 1, 1, 2, 1, 1, 1, 1, 14, - 有太多定义,对吧?我通常从没有到4个奇数(休息是一样的,它也可以是11, 11, 11, 4, 11 ...

我做错了吗?或rand()不是那么随意我认为是这样的? (或者它只是来自C#/ Java的一些我不知道的习惯?它对我来说也发生了很多......)

5 个答案:

答案 0 :(得分:4)

如果我运行该代码几次,我会得到不同的输出。当然,不像我想的那样变化,但看似不确定(虽然当然是,因为rand()只给出伪随机数......)。

然而,你对待你的数字的方式不会给你一个超过[1,20]的统一分布,我想这就是你所期望的。要实现这一目标要复杂得多,但绝不可能。举个例子,看一下documentation for <random> at cplusplus.com - 在底部有一个展示程序,可以在[0,1]上生成均匀分布。为了得到[1,20],您只需将输入参数更改为生成器 - 它可以在您喜欢的任何范围内为您提供均匀分布。

我做了一个快速测试,并拨打rand()一百万次。正如您在下面的输出中所看到的,即使样本量非常大,分布中也存在一些不均匀性。随着样本数量变为无穷大,该行将(可能)变平,使用类似rand() % 20 + 1的内容为您提供非常长时间的分发。如果您采取其他措施(如上面的示例),即使是非常小的样本量,您也可以更好地实现均匀分布。

1 million calls to rand()

修改
我看到其他几个人在发布使用它之前使用srand()播种随机数生成器。这是一个很好的建议,但在这种情况下它不会解决您的问题。我再说一遍:在这种情况下,播种不是问题。

种子主要用于控制程序输出的可重复性。如果使用常量值(例如0)对随机数进行种子处理,程序将每次都给出相同的输出,这对于测试一切是否正常工作非常有用。通过播种非常量的东西(当前时间是一种流行的选择),您可以确保结果在不同的程序运行之间有所不同。

根本不调用srand()与使用C ++标准调用srand(1)相同。因此,每次运行程序时都会得到相同的结果,但每次运行中都会有一系列完全有效的伪随机数。

答案 1 :(得分:3)

听起来你正在击中模拟偏见。

使用%将随机数缩放到某个范围并不是一个好主意。如果你将它降低到2的幂,但仍然相当差,这几乎是可以接受的。它主要受较小的比特的影响,这些比特在许多算法中经常不那么随机(特别是rand()),并且它以非均匀的方式收缩到较小的范围,因为你的减少的范围不会平均分配随机数生成器的范围。要缩小范围,您应该使用除法和循环,如下所示:

// generate a number from 0 to range-1
int divisor = MAX_RAND/(range+1);
int result;
do
{
    result = rand()/divisor;
} while (result >= range);

这并不像它看起来那么低效,因为循环几乎总是只传递一次。此外,如果你打算将你的生成器用于接近MAX_RAND的数字,你需要一个更复杂的divisor方程式,这是我无法记得的。

另外,rand()是一个非常差的随机数生成器,如果你关心结果的质量,可以考虑使用类似Mersenne Twister的东西。

答案 2 :(得分:2)

您需要先调用srand()并为其提供更好的伪随机值参数。

示例:

#include <iostream>
#include <string>
#include <vector>
#include "stdlib.h"
#include "time.h"

using namespace std;

int main()
{
    srand(time(0));
    int x,i;
    for (i=0; i<10; i++) {
        x = rand() % 20 + 1;
        cout << x << ", ";
    }
    system("pause");
    return 0;
}

如果您不希望重复生成的任何数字并且不需要考虑内存,则可以使用vector整数,随机随机播放,然后获取前N个整数的值。 / p>

示例:

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

int main()
{
    //Get 5 random numbers between 1 and 20
    vector<int> v;
    for(int i=1; i<=20; i++)
        v.push_back(i);
    random_shuffle(v.begin(),v.end());
    for(int i=0; i<5; i++)
        cout << v[i] << endl;
    system("pause");
    return 0;
}

答案 3 :(得分:0)

可能的问题是您每次使用相同的“随机”数字,并且任何int mod 1都为零。换句话说,(myInt % 1 == 0)总是如此。而不是%1,请使用% theBiggestNumberDesired

另外,使用srand为随机数播种。使用常量种子来验证您是否获得了良好的结果。然后更改种子以确保您仍然获得良好的结果。然后使用更随机的种子,如时钟进一步奶嘴。随机种子释放。

答案 4 :(得分:0)

注意:如果在不调用srand()的情况下在不同的线程中运行它,rand()会给你相同的结果。试着这样看看自己:

    vector<thread> workers;
    for (int i = 0; i < 10; i++)
        workers.push_back(std::thread([]{ cout << rand() << endl; }));

    for (auto& th : workers)
    {
        if (th.joinable())
            th.join();
    }