使用均值和标准差创建高斯随机生成器

18
我尝试创建一个一维数组,并使用随机数生成器(高斯分布生成器,生成均值为70,标准差为10的随机数)填充至少100个介于0到100之间的数字。在C++中,我应该如何做呢?
4个回答

30

C++11中,使用随机数头文件std::normal_distribution实时演示)可以相对简单地实现:

#include <iostream>
#include <iomanip>
#include <string>
#include <map>
#include <random>

int main()
{
    std::random_device rd;

    std::mt19937 e2(rd());

    std::normal_distribution<> dist(70, 10);

    std::map<int, int> hist;
    for (int n = 0; n < 100000; ++n) {
        ++hist[std::round(dist(e2))];
    }

    for (auto p : hist) {
        std::cout << std::fixed << std::setprecision(1) << std::setw(2)
                  << p.first << ' ' << std::string(p.second/200, '*') << '\n';
    }
}

如果C++11不是一个选项,那么boost也提供了一个库(实时示例):

#include <iostream>
#include <iomanip>
#include <string>
#include <map>
#include <random>
#include <boost/random.hpp>
#include <boost/random/normal_distribution.hpp>

int main()
{

  boost::mt19937 *rng = new boost::mt19937();
  rng->seed(time(NULL));

  boost::normal_distribution<> distribution(70, 10);
  boost::variate_generator< boost::mt19937, boost::normal_distribution<> > dist(*rng, distribution);

  std::map<int, int> hist;
  for (int n = 0; n < 100000; ++n) {
    ++hist[std::round(dist())];
  }

  for (auto p : hist) {
    std::cout << std::fixed << std::setprecision(1) << std::setw(2)
              << p.first << ' ' << std::string(p.second/200, '*') << '\n';
  }
}

如果出于某种原因,上述两种选项均不可行,则可以自己编写Box-Muller transform,链接提供的代码看起来合理。


谢谢你的回答。我正在阅读你提出的第一种方法,但是最后两个部分让我有点困惑,这最终意味着我不知道我们在哪里生成正态分布的数字。使用 std::map<int, int> hist; 部分和 for (int n = 0; n < 100000; ++n) {++hist[std::round(dist())];} 部分,我们实现了什么?然后是 for (auto p : hist) {... 部分?非常感谢您的帮助。 - user929304
@user929304 dist 生成正态分布的随机变量... hist 是用于显示结果并查看高斯图形的桶集合,查看实时示例可能会有所帮助。 - Shafik Yaghmour
非常感谢您的回复。我正在尝试使用实时示例,但仍然遇到困难。简而言之,我正在尝试编写一个循环(例如运行10次),在每次运行时,我会生成一个从高斯分布中选择的数字,该分布的平均值为0,方差为0.05。我已经完成了以下操作:std::random_device rd;``std::mt19937 e2(rd());``std::normal_distribution<float> dist(0, sqrt(0.05));``for (int i=0; i<10; i++){std::cout << dist(e2) << '\n';}它似乎可以工作,但我不知道为什么需要将e2传递给它?我理解rd是种子,但为什么我们需要e2 - user929304

11

使用Box Muller分布(来自这里):

double rand_normal(double mean, double stddev)
{//Box muller method
    static double n2 = 0.0;
    static int n2_cached = 0;
    if (!n2_cached)
    {
        double x, y, r;
        do
        {
            x = 2.0*rand()/RAND_MAX - 1;
            y = 2.0*rand()/RAND_MAX - 1;

            r = x*x + y*y;
        }
        while (r == 0.0 || r > 1.0);
        {
            double d = sqrt(-2.0*log(r)/r);
            double n1 = x*d;
            n2 = y*d;
            double result = n1*stddev + mean;
            n2_cached = 1;
            return result;
        }
    }
    else
    {
        n2_cached = 0;
        return n2*stddev + mean;
    }
}

你可以在此处阅读更多信息:wolframe math world


1
每次运行时,如何使其具有随机输出? - Wolfy
1
@Wolfy,是的!注意在rand_normal(double mean, double stddev)中使用了rand()函数。也许你忘记在使用此函数之前添加srand(time(NULL)),因此你总是得到相同的数字。 - samad montazeri

4
在C++11中,您可以使用<random>头文件提供的工具;创建一个随机引擎(例如std::default_random_enginestd::mt19937,如果需要则使用std::random_device进行初始化)和一个初始化了您参数的std::normal_distribution对象;然后您可以将它们结合起来生成您的数字。在这里,您可以找到一个完整的示例。
而在之前的C++版本中,则只有“经典”的C LCG(srand/rand),它只能生成范围为[0,MAX_RAND]的普通整数分布;但是您仍然可以使用Box-Muller变换来生成高斯随机数。(值得注意的是,C++11 GNU GCC libstdc++的std::normal_distribution使用Marsaglia极坐标法,如此处所示。)

2

使用 #include <random>

std::default_random_engine de(time(0)); //seed
std::normal_distribution<int> nd(70, 10); //mean followed by stdiv
int rarrary [101]; // [0, 100]
for(int i = 0; i < 101; ++i){
    rarray[i] = nd(de); //Generate numbers;
}

现在,我收到了错误:[错误]“default_random_engine”不是“std”的成员。 - coder_For_Life22

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接