一个C++11随机分布是由什么组成的

What is a C++11 random distribution made of?

本文关键字:什么 C++11 随机 分布 一个      更新时间:2023-10-16

我正在尝试实现以下类:

typedef std::mt19937 Engine;
class Interval 
{
public:
    double upperBoundary;
    double lowerBoundary;
    double generateUniformRandomNumber(Engine& engine);
};

我希望该类在多线程环境中工作。每个线程都有自己的Engine对象实例,并将Engine传递给任何具有随机化行为的类的对象。

为了以C++11的方式均匀地生成随机数,generateUniformRandomNumber的实现必须是这样的:

uniform_real_distribution<double> distribution_; // private member of Interval
double Interval::generateUniformRandomNumber(Engine& engine)
{
    return distribution_(engine); 
}

问题是我不了解C++11的发行版。我知道C++11随机数引擎可以是非常大的对象(几千字节(,但分布版呢?起初我认为分布只是简单的函子,其中operator()pure const函数,但它似乎既不是pure也不是const。根据参考文献,每个分发实例都有一个reset()成员函数。这意味着它有一个潜在的大的内部状态,或者可能有一个缓存。

我的问题是:

  1. 发行版有内部状态吗?如果是,为什么?标准对这个州的规模有什么规定吗?

  2. 像我一样进行实现是个好主意吗?有更好的方法吗?

一个分布可能非常好,通常会有一些状态。这里的标准没有任何限制。我能想到几个可能使用该状态的原因:

  1. 随机数分布通常有一些参数来配置它。例如,正态分布有均值和方差参数。这些是其状态的一部分,因为它们必须在调用之间保留。

  2. 该分发是根据其他一些分发来实现的。你真的可以把它看作一个更复杂的参数。例如,我的beta分布实现保留了两个gamma分布,每个gamma分布都有自己的配置。

  3. 分布可能会随着时间的推移而变化。没有什么可以说对分发的重复调用需要是独立的。这就是reset成员函数的作用所在。大多数发行版都有对operator()的独立调用,因此reset函数实际上什么都不做(其定义为空(。但是,如果您的调用是依赖的,reset应该会将分发恢复到下一个调用是独立的状态。

您的实现似乎很好。uniform_real_distribution<double>的状态不太可能比构造它的参数多得多。

查看文档以获取RandomNumberDistribution模板策略。。。

reset():

重置分发对象的内部状态。在呼叫后该函数是对分布对象的operator((的下一次调用将不依赖于以前对运算符((的调用。

这意味着对operator()的调用可以改变状态,从而影响对operator()的后续调用。这既是reset()存在的原因,也是operator()不是const的原因。

uniform_real_distribution应该是一个小的简单函子,就像你说的那样。它可能只容纳2个Real,而没有其他东西。reset()不应该对此做任何事情。

是的,分布可以有内部状态。它们通常很小,但如果你担心大小,请检查一下。

reset()的规范规定:

d的后续使用不依赖于任何引擎在调用reset之前生成的值。

这意味着operator()的正常调用可能取决于先前调用operator()时使用的引擎产生的值。也就是说,分发可以缓存或以其他方式依赖于以前的引擎结果。

例如,伯努利分布可能只需要一个比特来产生结果,而给定的引擎一次提供32个比特,因此该分布可能缓存32个比特并且在生成32个值之前不再次调用任何引擎。

另一个例子是一个分布(我忘记了是哪个(,其中公共算法一次自然产生两个值,因此该分布可能会为下一次调用保存第二个值。

所以,是的,分布可以有内部状态。该标准没有对该州的规模提出要求。

如果你问在线程之间共享分发是否可以,那么不可以,这不是一个好主意。首先,这样做是一种数据竞赛,会导致未定义的行为,除非您添加同步或使分发常量(即使您可以通过标准库的实现来实现,这也是不可移植的(。其次,该标准只在以特定方式使用分发和引擎时提供保证,而在多个引擎之间共享分发不是一种方式。共享一个分布不太可能真的会产生糟糕的数据,但国际海事组织不这样做仍然是个好主意。相反,您可能会让每个线程都保留自己的引擎和分布。