我是C ++的新手,但有数学背景。我正在尝试创建一个随机数生成器,它将在1.00和2.00之间吐出小数(美元金额),大致正态分布(因此平均值为1.50)。
现在,我从来没有尝试过这样的事情,也没有找到一个类似的问题,专门用正常分布的概率从一组数字中吐出一个元素。在这个模型中,1.50最有可能出现,1.00或2.00几乎没有机会出现。
写一篇p.d.f很容易。对于正态分布,其中均值= 1.50且3 * sigma = 0.5 - > sigma = 1/6(因此几乎所有数据都在1.00和2.00之间)。然而,不仅仅是不知道如何在这条曲线下整合101个区域(我不认为可以通过分析解析),它对我来说听起来并不高效。我知道C ++中有一个正常的分布函数。
有人可以帮我写一下这个评论吗?谢谢
答案 0 :(得分:5)
C ++标准库有normal distribution class - 正是您所要求的。使用它 - 并将值剪切到最小值和最大值之间:
#include <algorithm> // for std::clamp()
#include <iostream>
#include <random>
int main() {
std::random_device randomness_device{};
std::mt19937 pseudorandom_generator{randomness_device()};
auto mean = 1.5;
auto std_dev = 0.5;
auto min_allowed = 1.0;
auto max_allowed = 2.0;
std::normal_distribution<> distribution{mean, std_dev};
auto sample = distribution(pseudorandom_generator);
auto clamped =
// C++17 and later
std::clamp(sample, min_allowed, max_allowed);
// C++14 or earlier:
// std::max(min_allowed,std::min(sample, max_allowed));
//
std::cout
<< "A value from a normal distribution with mean " << mean
<< " and standard deviation " << std_dev << ": " << sample
<< "; when clamped to [" << min_allowed << ", "
<< max_allowed << "], we get: " << clamped << "\n";
}
就分布而言 - 这会改变度量,使整个范围(-infinity,1)集中在1,类似地(2,无穷大)集中在2.作为评论者,建议,还有其他方法解释您对“近似正常”分布的请求,例如重新采样,直到您达到所需范围内的值;或者应用将(无穷大,无穷大)映射到(1,2)的连续变换,例如, x - &gt;反正切(X)。但你没有具体说明你究竟是在追求什么。
答案 1 :(得分:3)
添加到其他答案,您可以使用(伪)unform随机数生成器通过Polar method
创建正常的随机数生成器示例代码:
#include <math.h>
#include <stdlib.h>
double
randn (double mu, double sigma)
{
double U1, U2, W, mult;
static double X1, X2;
static int call = 0;
if (call == 1)
{
call = !call;
return (mu + sigma * (double) X2);
}
do
{
U1 = -1 + ((double) rand () / RAND_MAX) * 2;
U2 = -1 + ((double) rand () / RAND_MAX) * 2;
W = pow (U1, 2) + pow (U2, 2);
}
while (W >= 1 || W == 0);
mult = sqrt ((-2 * log (W)) / W);
X1 = U1 * mult;
X2 = U2 * mult;
call = !call;
return (mu + sigma * (double) X1);
}
接下来,您可以使用它来获取应用程序的正态分布随机数。
答案 2 :(得分:2)
您可以使用std::normal_distribution<>
。
它会从double
数据类型的整个范围生成样本,但您可以在您感兴趣的区间之外丢弃样本,并且您仍将接近具有三西格玛的正态分布。
#include <iostream>
#include <random>
using namespace std;
int main()
{
auto mean = 1.5,
stddev = 1.0 / 6;
// Create a normal distribution to pull samples from
// The distribution has mean 1.5 and ~1/6 std dev
random_device rd;
mt19937_64 generator(rd());
normal_distribution<> distribution(mean, stddev);
cout << "some samples:" << endl;
for (int i = 0; i < 10; ++i)
{
// Generate a sample. The sample will be in (-infinity, infinity), so
// we throw away values that are outside of 3 std devs.
// The distribution will no longer be normal, but close enough.
double v;
do
{
v = distribution(generator);
} while (v < mean - 3 * stddev || v >= mean + 3 * stddev);
cout << v << endl;
}
return 0;
}
some samples:
1.70539
1.49569
1.53731
1.42872
1.34029
1.54886
1.66154
1.54685
1.60833
1.36282