C++11随机数分布在不同平台上不一致--有哪些替代方案?

18

我正在寻找一组可移植的分发版本,用于标准C++11引擎,如`std::mt19937' (请参见http://en.cppreference.com/w/cpp/numeric/random)。

引擎实现表现一致(即在不同平台上生成相同的序列 - 在Clang和MSVC下进行了测试),但是似乎在不同平台上实现了不同的分布。

因此,即使引擎产生相同的序列,也似乎分布(例如,std::normal_distribution<double>)在不同平台上使用不同数量的样本(即产生不同的结果),这在我的情况下是不可接受的。

也许有第三方库遵循C++11随机模板,但可以在流行的平台上提供一致的值吗(查看GCC、MSVC和Clang / llvm的支持)。

到目前为止,我看过的选项有:

  • Boost.random(有点重,但值得,因为它与c++11对应物相当匹配)
  • 克隆自libstd++ (也值得,可能是可移植的,但提取特定函数可能不简单)
  • 创建自己的类似于C++11的随机分布

我需要均匀、正常、泊松和瑞利。


2
你需要的是boost随机数库吗? - shuttle87
@shuttle87,我已经在逐步清除代码库中的所有boost依赖,所以不太想再引入boost库了。 - Arno Duvenhage
@shuttle87 Boost.Random能否保证在不同平台上产生相同的结果? - Arno Duvenhage
请注意,“C++11模板”实际上是由您的编译器提供的模板。这些受版权保护!通常这不是问题,因为您可以使用与匹配编译器一起使用的标准库。但是,您不能只是将GCC发行版与MSVC或反之互用。 - MSalters
1
遇到了这个链接:http://www.johndcook.com/blog/cpp_random_number_generation/ 看起来非常完整,但是我需要适配分布以与C++11引擎一起使用。 - Arno Duvenhage
显示剩余6条评论
1个回答

17

我已经创建了自己的C++11发行版:

template <typename T>
class UniformRealDistribution
{
 public:
    typedef T result_type;

 public:
    UniformRealDistribution(T _a = 0.0, T _b = 1.0)
        :m_a(_a),
         m_b(_b)
    {}

    void reset() {}

    template <class Generator>
    T operator()(Generator &_g)
    {
        double dScale = (m_b - m_a) / ((T)(_g.max() - _g.min()) + (T)1); 
        return (_g() - _g.min()) * dScale  + m_a;
    }

    T a() const {return m_a;}
    T b() const {return m_b;}

 protected:
    T       m_a;
    T       m_b;
};

template <typename T>
class NormalDistribution
{
 public:
    typedef T result_type;

 public:
    NormalDistribution(T _mean = 0.0, T _stddev = 1.0)
        :m_mean(_mean),
         m_stddev(_stddev)
    {}

    void reset()
    {
        m_distU1.reset();
    }

    template <class Generator>
    T operator()(Generator &_g)
    {
        // Use Box-Muller algorithm
        const double pi = 3.14159265358979323846264338327950288419716939937511;
        double u1 = m_distU1(_g);
        double u2 = m_distU1(_g);
        double r = sqrt(-2.0 * log(u1));
        return m_mean + m_stddev * r * sin(2.0 * pi * u2);
    }

    T mean() const {return m_mean;}
    T stddev() const {return m_stddev;}

protected:
    T                           m_mean;
    T                           m_stddev;
    UniformRealDistribution<T>  m_distU1;
};

均匀分布似乎可以提供不错的结果,而正态分布则可以提供非常好的结果:
100000个值 -> 1σ内68.159%; 2σ内95.437%; 3σ内99.747%。
正态分布使用Box-Muller方法,根据我目前所读到的,这并不是最快的方法,但对于我的应用程序来说,它运行得足够快。
均匀分布和正态分布都应该适用于任何C++11引擎(已测试std :: mt19937),并且在所有平台上提供相同的序列,这正是我想要的。

这只适用于浮点数吗?我在我的项目中尝试了使用整数范围,但是却出现了“浮点异常”的错误。 - thomthom
仅用于浮点数,但我不明白为什么会出现异常。 - Arno Duvenhage
当给定一个整数时,你会得到一个除零异常。 - thomthom
是的,正态分布依赖于真实均匀分布。请参见https://stackoverflow.com/questions/22016007/how-can-i-create-a-normal-integer-distribution-in-c11 - Arno Duvenhage

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接