7

问题是我需要生成一个介于 0 到 999 之间的随机整数(用于研究数学猜想)。所有值都需要具有相同的出现概率。

我已经尝试过rand(),但是RAND_MAX32767 (在我的编译器上)这意味着仅rand() % 1000导致第一个 1-767 出现的可能性要大得多(这是假设所有可能性rand()首先具有相同的概率)。

我正在使用 Windows,所以/dev/random不是一个选项。

4

6 回答 6

24

您可以使用uniform_int_distributionC++11 执行以下操作:

#include <iostream>
#include <random>

int main()
{
    std::random_device rd;
    std::mt19937 gen(rd());
    std::uniform_int_distribution<> dis(0, 999);

    for (int n=0; n<1000; ++n)
        std::cout << dis(gen) << ' ';
    std::cout << '\n';
}
于 2013-04-22T17:59:56.903 回答
10

您的模数观察是正确的,并且是无法经受数学审查的几个原因之一。rand()这里的注释

不保证产生的随机序列的质量。过去,rand() 的一些实现在产生的序列的随机性、分布和周期方面存在严重缺陷(在一个众所周知的示例中,低位位在调用之间简单地在 1 和 0 之间交替)。rand() 不推荐用于严重的随机数生成需求,例如密码学。

C++11 引入了几个新的随机数生成器,它们遵循更严格的标准,可能适合您的目的。

如果您可以牺牲超过几个字节的开销(可以肯定地假设可以),我建议std::mersenne_twister_engine

于 2013-04-22T18:00:08.580 回答
3

我认为最简单的方法是扔掉区间中的数字[32000, 32767],只将 应用于% 1000剩余的数字。这应该使您的分布更加均匀。

或者,您可以使用 boost 的随机/均匀分布组件(或 C++11 如果可用),因为它们将提供比rand.

于 2013-04-22T17:59:43.887 回答
1

问题是 rand() 为您提供域[0,RAND_MAX]RAND_MAX的均匀分布变量,最有可能是 32767。您不能通过简单的乘法将此域映射到更大的域

u=(double)rand();
d=(double)RAND_MAX;
double div= u/d;
double res=div*interval_range;

因为只有当 RAND_MAX 是 的偶数倍时,这才是正确的interval_range。但是,您将不会在更大的域中拥有所有值。但是,如果您的新的所需域小于RAND_MAX您的情况,您可以将生成的均匀分布截断rand()到您想要的域(本质上意味着拒绝rand()大于您所需域的值)。截断的均匀分布仍然是均匀的,因此您将在新域上拥有新的均匀分布变量(这将是更准确的条件分布)。统计示例:

在此处输入图像描述

所以截断的均匀分布将有另一个“时刻”,描述它的参数(均值、std_dev、方差等)但将再次均匀。

示例代码:

int main{ 
    int o=RAND_MAX;
    std::map<int,int> m1;
    int min=0,max=999;

    for (int i=0; i<1000*9994240; ++i){//9994240=305*32768  32768=RAND_MAX+1
        int r=rand();
        if(r<=max){
            m1[r]++;
        }
    }
    for (auto & i : m1)
        std::cout << i.first << " : " << i.second << '\n';
}

result: 0 : 42637 1 : 42716 2 : 42590 3 : 42993 4 : 42936 5 : 42965 6 : 42941 7 : 42705 8 : 42944 9 : 42707 10 : 42860 11 : 43012 12 : 42793 //... 995 : 42861 996 : 42911 997 : 42865 998 : 42877 999 : 43159


您可以通过这种方式在任何域上获得所需的结果:

#include <iostream>
#include <random>

int main()
{
    std::random_device rd;
    std::mt19937 gen(rd());
    std::uniform_int_distribution<> dis(0, 1000);

    for (int n=0; n<1000; ++n)
        std::cout << dis(gen) << ' ';
    std::cout << '\n';
}

但是在这种情况下你真的应该使用 boost:

#include <iostream>
#include "boost/random.hpp"
#include "boost/generator_iterator.hpp"
using namespace std;

int main() {
      typedef boost::mt19937 RNGType;
      RNGType rng;
      boost::uniform_int<> zero_to_n( 0, 999 );
      boost::variate_generator< RNGType, boost::uniform_int<> >
                    dice(rng, zero_to_n);
          int n  = dice();

}
于 2013-04-22T18:04:22.477 回答
0
  1. 使用 获取随机数rand()

  2. 将其除以RAND_MAX。您将获得一个介于 0 和 1 之间的浮点数。

  3. 将此数字乘以 1000。

于 2013-04-22T18:00:24.967 回答
0

计算机中没有“真正随机”这样的东西。我也不相信 1-767(或技术上,在这种情况下为 0-767)的机会明显高于任何其他数字。但是,如果您需要“更好”的随机数,那么 C++11 支持使用 Mersenne Twister,这是一种更高等级的随机数生成器。

更多信息在这里: http ://www.cplusplus.com/reference/random/mt19937/

于 2013-04-22T18:00:53.003 回答