c++ - 如何使用正态分布生成最小值和最大值之间的整数?

标签 c++ c++11 random integer normal-distribution

我了解到我们使用

 unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
 std::default_random_engine generator (seed);
 std::normal_distribution<double> distribution (mean_value,variance_value);

生成实数。但我不知道如何为这一代给出一个范围(最小值和最大值)以及如何在这种情况下仅生成整数。对于uniform_distribution,它是直接的。有人可以帮忙吗?谢谢!

最佳答案

嗯,您可以根据给定点的正态分布计算概率,并将其用于离散采样。

沿着线

#include <cmath>
#include <random>
#include <iostream>

constexpr double PI = 3.14159265359;

static inline double squared(const double x) {
    return x * x;
}

double GaussPDF(const double x,
                const double mu,
                const double sigma) {
    return exp(-0.5 * squared((x - mu) / sigma)) / (sqrt(2.0 * PI) * sigma);
}

int SampleTruncIntGauss(const int xmin, const int xmax, const double mu, const double sigma, std::mt19937_64& rng) {
    int n = xmax - xmin + 1;
    std::vector<double> p(n);
    for (int k = 0; k != n; ++k)
        p[k] = GaussPDF(static_cast<double>(xmin) + k, mu, sigma);

    std::discrete_distribution<int> igauss{ p.begin(), p.end() };

    return xmin + igauss(rng);
}

int main() {

    int xmin = -3;
    int xmax =  5;
    int n = xmax - xmin + 1;

    double mu = 1.2;
    double sigma = 2.3;

    std::mt19937_64 rng{ 98761728941ULL };

    std::vector<int> h(n, 0);

    for (int k = 0; k != 10000; ++k) {
        int v = SampleTruncIntGauss(xmin, xmax, mu, sigma, rng);
        h[v - xmin] += 1;
    }

    int i = xmin;
    for (auto k : h) {
        std::cout << i << "   " << k << '\n';
        ++i;
    }

    return 0;
}

您可以使代码更加优化,每次采样时我都会重新初始化概率数组,但它演示了这个想法的要点。

更新

您还可以使用非点概率进行采样,基本上假设整数点 x 处的概率表示值在 [x-0.5...x+0.5] 范围内的概率。这可以通过高斯 CDF 轻松表达。

constexpr double INV_SQRT2 = 0.70710678118;

double GaussCDF(const double x,
                const double mu,
                const double sigma) {
    double v = INV_SQRT2 * (x - mu) / sigma;
    return 0.5 * (1.0 + erf(v));
}

double ProbCDF(const int    x,
               const double mu,
               const double sigma) {
    return GaussCDF(static_cast<double>(x) + 0.5, mu, sigma) - GaussCDF(static_cast<double>(x) - 0.5, mu, sigma);
}

概率代码为

for (int k = 0; k != n; ++k) {
    p[k] = ProbCDF(xmin + k, mu, sigma);

结果略有不同,但仍然类似于高斯

关于c++ - 如何使用正态分布生成最小值和最大值之间的整数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56132153/

相关文章:

c++ - VS 2012 中的可变参数模板(Visual C++ 2012 年 11 月 CTP)

python - Python 中形状的随机填充颜色(TKinter)

c++ - 在现代 OpenGL 和 C++ 中渲染 Quake BSP

C++:打印/分配简单数组打印乱码

c++ - 使用 lambda 的简单 RAII 包装器的复制初始化在 GCC 和 Clang 下意外失败

c++ - 可变参数模板复杂继承生成

c++ - 在派生类中可见的私有(private) typedef

c++ - 用非零值填充内存比用零填充内存慢吗?

javascript - 如何从哈希中获取数字

variables - `tf.random_normal` 和 `tf.random_normal_initializer` 有什么区别?