简体   繁体   English

我可以使用单个“ default_random_engine”来创建多个正态分布的数字集吗?

[英]Can I use a single `default_random_engine` to create multiple normally distributed sets of numbers?

I want to generate a set of unit vectors (for any arbitrary dimension), which are evenly distributed across all directions. 我想生成一组单位矢量(对于任意尺寸),这些单位矢量在所有方向上均匀分布。 For this I generate normally distributed numbers for each vector component and scale the result by the inverse of the magnitude. 为此,我为每个矢量分量生成正态分布的数字,并按幅度的倒数来缩放结果。

My question : Can I use a single std::default_random_engine to generate numbers for all components of my vector or does every component require its own engine? 我的问题 :我可以使用单个std::default_random_engine为矢量的所有分量生成数字,还是每个分量都需要自己的引擎?

Afaik, each component needs to be Gaussian-distributed independently for the math to work out and I cannot assess the difference between the two scenarios. Afaik,每个部分都需要独立分配高斯分布,以便数学计算出来,而我无法评估这两种情况之间的差异。 Here's a MWE with a single RNG (allocation and normalization of vectors is omitted here). 这是具有单个RNG的MWE(此处省略了向量的分配和规范化)。

std::vector<std::vector<double>> GenerateUnitVecs(size_t dimension, size_t count)
{
    std::vector<std::vector<double>> result;

    /* Set up a _single_ RNG */
    size_t seed = GetSeed(); // system_clock
    std::default_random_engine gen(seed);
    std::normal_distribution<double> distribution(0.0, 1.0); 

    /* Generate _multiple_ (independent?) distributions */
    for(size_t ii = 0; ii < count; ++ii){
        std::vector<double> vec;
        for(size_t comp = 0; comp < dimension; ++comp)
            vec.push_back(distribution(gen)); // <-- random number goes here

        result.push_back(vec);
    }
    return result;
}

Thank you. 谢谢。

I am assuming you are not generating random numbers in parallel. 我假设您不是并行生成随机数。 Then theoretically, there is no problem with generating random independent Gaussian vectors with one engine. 从理论上讲,用一个引擎生成随机独立的高斯矢量没有问题。

Each call to std::normal_distribution 's () operator gives you a random real-valued number following specified Gaussian distribution. std::normal_distribution()运算符的每次调用std::normal_distribution按照指定的高斯分布为您提供一个随机的实数值。 Successive calls of () operator give you independent samples. ()运算符的连续调用为您提供了独立的样本。 The implementation in gcc (my version: 4.8 ) uses the Marsaglia Polar method for standard normal random number generation. gcc (我的版本: 4.8 )中的实现使用Marsaglia Polar方法生成标准的正常随机数。 You can read this Wikipedia page for more detail. 您可以阅读 Wikipedia页面以获取更多详细信息。

However, for rigorous scientific research that demands high quality randomness and a huge amount of random samples, I would recommend using the Mersenne-Twister engine ( mt19937 32-bit or 64-bit) instead of the default engine, since it is based on a well-established method, has long period and performs well on statistical random tests. 但是,对于需要高质量随机性和大量随机样本的严格科学研究,我建议使用Mersenne-Twister引擎mt19937 32位或64位)而不是默认引擎,因为它基于a完善的方法,周期长,在统计随机检验中表现良好。

The OP asked: OP问:

My question: Can I use a single std::default_random_engine to generate numbers for all components of my vector or does every component require its own engine? 我的问题:我可以使用单个std :: default_random_engine为向量的所有分量生成数字,还是每个分量都需要自己的引擎?


I would suggest as others have stated in the comments about not using std::default_random_engine and instead use std::random_device or std::chrono::high_resolution_clock 我建议像其他人在评论中所述,关于不使用std::default_random_engine而不是使用std::random_devicestd::chrono::high_resolution_clock std::random_device


To use random_device for a normal distribution or Gaussian it is quite simple: 要将random_device用于normal distributionGaussian normal distribution ,这非常简单:

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

int main() {

    std::random_device rd{};
    std::mt19937 gen{ rd() };

    // values near the mean are the most likely
    // standard deviation affects the dispersion of generated values from the mean
    std::normal_distribution<> d{5,2};

    std::map<int, int> hist{};
    for ( int n=0; n<10000; ++n ) {
        ++hist[std::round(d(gen))];
    }
    for ( auto p : hist ) {
        std::cout << std::setw(2)
                  << p.first << ' ' << std::string(p.second/200, '*' ) << '\n';
    }
}

To use std::chrono::high_resolution_clock : there is a little more work but just as easy. 要使用std::chrono::high_resolution_clock :还有更多工作,但同样简单。

#include <iostream>
#include <iomanip>
#include <string>
#include <map>
#include <random>
#include <cmath>
#include <limits>
#include <chrono>

class ChronoClock {
public:
    using Clock = std::conditional_t<std::chrono::high_resolution_clock::is_steady,
        std::chrono::high_resolution_clock,
        std::chrono::steady_clock>;

    static unsigned int getTimeNow() {
        unsigned int now = static_cast<unsigned int>(Clock::now().time_since_epoch().count());
        return now;
    }
};

int main() {       

    /*static*/ std::mt19937 gen{}; // Can be either static or not.

    gen.seed( ChronoClock::getTimeNow() );

    // values near the mean are the most likely
    // standard deviation affects the dispersion of generated values from the mean
    std::normal_distribution<> d{5,2};

    std::map<int, int> hist{};
    for ( int n=0; n<10000; ++n ) {
        ++hist[std::round(d(gen))];
    }
    for ( auto p : hist ) {
        std::cout << std::setw(2)
                  << p.first << ' ' << std::string(p.second/200, '*' ) << '\n';
    }
}

As you can see from the examples above where these are shown here from cppreference.com there is a single engine, single seed, and a single distribution, that it is generating random numbers or sets of random numbers with a single engine. 从上面的示例中可以看到,这些示例 cppreference.com上显示,它们具有单个引擎,单个种子和单个分发,它使用单个引擎生成随机数或随机数集。


EDIT - Additionally you can use a class that I've written as a wrapper class for random engines and random distributions . 编辑 - 另外,您可以将我作为封装类编写的类用于random enginesrandom distributions You can refer to this answer of mine here . 您可以在这里参考我的答案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM