在Stackoverflow中,有许多关于从未知范围生成均匀分布的整数的问题。例如
典型的解决方案是这样的:
inline std::mt19937 &engine()
{
  thread_local std::mt19937 eng;
  return eng;
}
int get_int_from_range(int from, int to)
{
  std::uniform_int_distribution<int> dist(from, to);
  return dist(engine());
}
下面的实现可靠吗?
int get_int_from_range(int from, int to)
{
  using distribution_type = std::uniform_int_distribution<int>;
  using param_type = typename distribution_type::param_type;
  thread_local std::uniform_int_distribution<int> dist;
  return dist(engine(), param_type(from, to));    
}
发布于 2018-04-28 21:25:18
有趣的问题。
所以我想知道是否会通过不断重置它来干扰分配的工作方式(即在每次调用get_int_from_range时重新创建分配),我会得到正确分配的结果。
我已经编写了代码来测试这个uniform_int_distribution和poisson_distribution。如果你愿意,可以很容易地扩展它来测试另一个发行版。答案是肯定的。
代码:
#include <random>
#include <memory>
#include <chrono>
#include <utility>
typedef std::mt19937_64 engine_type;
inline size_t get_seed()
    { return std::chrono::system_clock::now().time_since_epoch().count(); }
engine_type& engine_singleton()
{  
    static std::unique_ptr<engine_type> ptr;
    if ( !ptr ) 
        ptr.reset( new engine_type(get_seed()) );
    return *ptr;
}
// ------------------------------------------------------------------------
#include <cmath>
#include <cstdio>
#include <vector>
#include <string>
#include <algorithm>
void plot_distribution( const std::vector<double>& D, size_t mass = 200 )
{
    const size_t n = D.size();
    for ( size_t i = 0; i < n; ++i ) 
    {
        printf("%02ld: %s\n", i, 
            std::string(static_cast<size_t>(D[i]*mass),'*').c_str() );
    }
}
double maximum_difference( const std::vector<double>& x, const std::vector<double>& y )
{
    const size_t n = x.size(); 
    double m = 0.0;
    for ( size_t i = 0; i < n; ++i )
        m = std::max( m, std::abs(x[i]-y[i]) );
    return m;
}
实际测试代码:
#include <iostream>
#include <vector>
#include <cstdio>
#include <random>
#include <string>
#include <cmath>
void compare_uniform_distributions( int lo, int hi )
{
    const size_t sample_size = 1e5;
    // Initialize histograms
    std::vector<double> H1( hi-lo+1, 0.0 ), H2( hi-lo+1, 0.0 );
    // Initialize distribution
    auto U = std::uniform_int_distribution<int>(lo,hi);
    // Count!
    for ( size_t i = 0; i < sample_size; ++i )
    {
        engine_type E(get_seed());
        H1[ U(engine_singleton())-lo ] += 1.0;
        H2[ U(E)-lo ] += 1.0;
    }
    // Normalize histograms to obtain "densities"
    for ( size_t i = 0; i < H1.size(); ++i )
    {
        H1[i] /= sample_size; 
        H2[i] /= sample_size; 
    }
    printf("Engine singleton:\n"); plot_distribution(H1);
    printf("Engine creation :\n"); plot_distribution(H2);
    printf("Maximum difference: %.3f\n", maximum_difference(H1,H2) );
    std::cout<< std::string(50,'-') << std::endl << std::endl;
}
void compare_poisson_distributions( double mean )
{
    const size_t sample_size = 1e5;
    const size_t nbins = static_cast<size_t>(std::ceil(2*mean));
    // Initialize histograms
    std::vector<double> H1( nbins, 0.0 ), H2( nbins, 0.0 );
    // Initialize distribution
    auto U = std::poisson_distribution<int>(mean);
    // Count!
    for ( size_t i = 0; i < sample_size; ++i )
    {
        engine_type E(get_seed());
        int u1 = U(engine_singleton());
        int u2 = U(E);
        if (u1 < nbins) H1[u1] += 1.0;
        if (u2 < nbins) H2[u2] += 1.0;
    }
    // Normalize histograms to obtain "densities"
    for ( size_t i = 0; i < H1.size(); ++i )
    {
        H1[i] /= sample_size; 
        H2[i] /= sample_size; 
    }
    printf("Engine singleton:\n"); plot_distribution(H1);
    printf("Engine creation :\n"); plot_distribution(H2);
    printf("Maximum difference: %.3f\n", maximum_difference(H1,H2) );
    std::cout<< std::string(50,'-') << std::endl << std::endl;
}
// ------------------------------------------------------------------------
int main()
{
    compare_uniform_distributions( 0, 25 );
    compare_poisson_distributions( 12 );
}
https://stackoverflow.com/questions/-100008312
复制相似问题