【发布时间】:2013-11-25 11:36:14
【问题描述】:
我正在尝试创建一个一维数组并使用随机数生成器(生成平均值为 70 且标准差为 10 的随机数的高斯生成器)在数组中填充至少 100 个介于 0 和 100 之间的数字包括在内。
我将如何在 C++ 中执行此操作?
【问题讨论】:
标签: c++ random gaussian normal-distribution
我正在尝试创建一个一维数组并使用随机数生成器(生成平均值为 70 且标准差为 10 的随机数的高斯生成器)在数组中填充至少 100 个介于 0 和 100 之间的数字包括在内。
我将如何在 C++ 中执行此操作?
【问题讨论】:
标签: c++ random gaussian normal-distribution
在 C++11 中,使用 random header 和 std::normal_distribution (live example) 相对简单:
#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 也提供了一个库(live example):
#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) {... 部分实现了什么?提前致谢。
dist 生成正常的随机变量...hist 是一组用于显示结果以查看高斯图的存储桶,查看实时示例可能会有所帮助。
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?
使用 Box Muller 分布(来自here):
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
【讨论】:
rand() 内的rand_normal(double mean, double stddev) 函数。也许您在使用此功能之前缺少srand(time(NULL)),因此您总是得到相同的数字。
在 C++11 中,您将使用 <random> 标头提供的功能;创建一个随机引擎(例如std::default_random_engine 或std::mt19937,必要时使用std::random_device 初始化)和一个使用您的参数初始化的std::normal_distribution 对象;然后你可以一起使用它们来生成你的数字。 Here你可以找到一个完整的例子。
在以前的 C++ 版本中,您所拥有的只是“经典”C LCG (srand/rand),它只生成 [0, MAX_RAND] 范围内的普通整数分布;有了它,您仍然可以使用Box-Muller transform 生成高斯随机数。 (请注意,C++11 GNU GCC libstdc++ 的 std::normal_distribution 使用 Marsaglia polar method,如 herein 所示。)。
【讨论】:
与#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;
}
【讨论】: