为什么C ++ 11随机分布是可变的? [英] Why are c++11 random distributions mutable?

查看:74
本文介绍了为什么C ++ 11随机分布是可变的?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我认为c ++ 11随机分布(例如uniform_int_distribution)生成的值仅取决于传递给operator()的生成器的状态.但是,由于某些原因,operator()的签名中没有const说明符.这是什么意思,我应该如何将分布作为函数参数传递?我以为我必须将其作为任何非可变参数传递:通过const引用,但是现在我不确定.

I thought that the value generated by the c++11 random distribution (uniform_int_distribution, for instance), depends only on the state of the generator which is passed to the operator(). However, for some reason there is no const specifier in the signature of operator(). What does that mean, and how should I pass the distribution as a function parameter? I thought I had to pass it as any non-mutable parameter: by const reference, but now I'm not sure.

推荐答案

起初我误解了这个问题,但是,据我所知,这是一个很好的问题.对g ++的<random>实现的实现进行了一些深入研究,得出以下内容(为清楚起见,省略了一些内容):

I misunderstood the question at first, however, now that I understand, it's a good question. Some digging into the source of the implementation of <random> for g++ gives the following (with a few bits left out for clarity):

template<typename _IntType = int>
  class uniform_int_distribution
  {

  struct param_type
  {
    typedef uniform_int_distribution<_IntType> distribution_type;

    explicit
    param_type(_IntType __a = 0,
       _IntType __b = std::numeric_limits<_IntType>::max())
    : _M_a(__a), _M_b(__b)
    {
      _GLIBCXX_DEBUG_ASSERT(_M_a <= _M_b);
    }

     private:
    _IntType _M_a;
    _IntType _M_b;
};

public:
  /**
   * @brief Constructs a uniform distribution object.
   */
  explicit
  uniform_int_distribution(_IntType __a = 0,
           _IntType __b = std::numeric_limits<_IntType>::max())
  : _M_param(__a, __b)
  { }

  explicit
  uniform_int_distribution(const param_type& __p)
  : _M_param(__p)
  { }

  template<typename _UniformRandomNumberGenerator>
result_type
operator()(_UniformRandomNumberGenerator& __urng)
    { return this->operator()(__urng, this->param()); }

  template<typename _UniformRandomNumberGenerator>
result_type
operator()(_UniformRandomNumberGenerator& __urng,
       const param_type& __p);

  param_type _M_param;
};

如果我们斜视所有的_,我们可以看到它只有一个成员参数param_type _M_param,它本身就是一个嵌套结构,它包含2个整数值-实际上是一个范围. operator()仅在此处声明,未定义.一些更多的挖掘将我们带到了定义.代替在此处发布所有代码(这很丑陋(而且相当长)),只需说此函数中没有任何变化即可.实际上,在定义和声明中添加const会很容易地进行编译.

If we squint past all the _, we can see that it has only a single member parameter, param_type _M_param, which itself is simply a nested struct holding 2 integral values - in effect, a range. operator() is only declared here, not defined. Some more digging brings us to the definition. In lieu of posting all the code here, which is pretty ugly (and rather long), it suffices to say that nothing is mutated inside this function. In fact, adding const to definition and declaration will happily compile.

问题就变成了,其他所有发行版都这样吗?答案是不.如果我们查看std::normal_distribution的实现,则会发现:

The question then becomes, is this true for every other distribution? The answer is no. If we look to the implementation for std::normal_distribution, we find:

template<typename _RealType>
template<typename _UniformRandomNumberGenerator>
  typename normal_distribution<_RealType>::result_type
  normal_distribution<_RealType>::
  operator()(_UniformRandomNumberGenerator& __urng,
     const param_type& __param)
  {
result_type __ret;
__detail::_Adaptor<_UniformRandomNumberGenerator, result_type>
  __aurng(__urng);

    //Mutation!
if (_M_saved_available)
  {
    _M_saved_available = false;
    __ret = _M_saved;
  }
    //Mutation!

这仅是理论上的问题,但我想它不限于const的原因是允许实现者根据需要更改其实现.此外,它保持了更统一的界面-如果某些operator()const而某些不是-const,那么它们都将变得有些混乱.

This is all just theorizing, but I imagine the reason it is not restricted to const is to allow implementers to mutate their implementation if required. Further, it keeps a more uniform interface - if some operator() are const and some are non-const, it all becomes a bit messy.

但是,为什么不能简单地使它们成为const并让实现者利用mutable,我不确定.可能的是,除非周围有人参与了标准化工作的这一部分,否则您可能无法获得很好的答案.

However, why they didn't simply make them const and let the implementers utilize mutable I'm not sure. Likely, unless someone around here was involved with this part of the standardization effort, you may not get a good answer to this.

正如MattieuM所指出的,mutable和多个线程不能很好地配合使用.

As MattieuM pointed out, mutable and multiple threads do not play nicely together.

除了一个不太有趣的内容外,std::normal_distribution一次生成两个值,并缓存一个(因此,_M_saved).它定义的operator<<实际上使您可以在下次调用operator()之前看到此值:

Just as a minorly interesting aside, std::normal_distribution generates two values at once, caching one (hence the _M_saved). The operator<< that it defines actually lets you see this value before the next call to operator():

#include <random>
#include <iostream>
#include <chrono>

std::default_random_engine eng(std::chrono::system_clock::now().time_since_epoch().count());
std::normal_distribution<> d(0, 1);

int main()
{
   auto k = d(eng);
   std::cout << k << "\n";
   std::cout << d << "\n";
   std::cout << d(eng) << "\n";
}

在这里,输出格式为mu sigma nextval.

这篇关于为什么C ++ 11随机分布是可变的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆