繁体   English   中英

rand()给出了相同的值

[英]rand() gives still the same value

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

例如

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

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

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

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

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

我做了一个快速测试,并称为rand()一百万次。 正如您在下面的输出中所看到的,即使样本量非常大,分布中也存在一些不均匀性。 当样本数量变为无穷大时,该行将(可能)变平,使用rand() % 20 + 1会给你一个需要长时间才能完成的分布。 如果您采取其他措施(如上面的示例),即使样本量非常小,您也可以更好地实现均匀分布。

100万次调用rand()

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

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

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

听起来你正在达到模数偏见

使用%将随机数缩放到范围不是一个好主意。 如果你将它降低到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这样的东西。

您需要先调用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个int的值。

例:

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

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

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

注意:如果你在不同的线程中运行它而没有调用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();
    }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM