需要一个正态分布的随机数生成器

Need a normally-distributed random number generator

我是 C++ 新手,但有数学背景。我正在尝试创建一个随机数生成器,它将吐出一个介于 1.00 和 2.00 之间的小数(美元金额),具有近似正态分布(因此平均值为 1.50)。

现在,我从来没有尝试过这样的事情,也没有找到类似的问题,专门从一组具有正态分布概率的数字中吐出一个元素。在这个模型中,1.50最有可能出现,1.00或2.00几乎没有机会出现。

写一个 p.d.f 很容易。对于 mean=1.50 和 3*sigma = 0.5 --> sigma = 1/6 的正态分布(因此几乎所有数据都在 1.00 和 2.00 之间)。然而,不仅仅是不知道如何用 C++ 集成这条曲线下的 101 个区域(我认为这不能通过分析解决),它对我来说听起来效率不高。我知道C++有正态分布函数

有人可以帮我写出来,并附上评论吗?谢谢

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,infinity) 集中在 2。作为评论者,建议,有其他解释您对 "approximately normal" 分布的请求的方法,例如重新采样,直到您达到所需范围内的值;或应用将 (infinity, infinity) 映射到 (1,2) 的连续变换,例如x -> arctan(x)。但是你没有具体说明你到底在追求什么。

您可以为此使用 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

添加到其他答案中,您可以使用(伪)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);
}

接下来,您可以使用它来为您的应用程序获取正态分布的随机数。