【问题标题】:Should I keep the random distribution object instance or can I always recreate it?我应该保留随机分布对象实例还是可以随时重新创建它?
【发布时间】:2012-01-16 00:47:35
【问题描述】:

我有这个代码:

static std::mt19937 rnd;

// ...

static uint32_t rndInt(uint32_t min, uint32_t max) {
    return std::uniform_int_distribution<uint32_t>(min,max)(rnd);
}

这是好的做法还是我应该存储uniform_int_distribution

【问题讨论】:

标签: c++ random c++11


【解决方案1】:

我一般会做以下事情:

std::uniform_int_distribution<uint32_t> distrib(16, 97);

然后您可以多次调用distrib(rnd),而无需每次都重新生成分布。

您执行操作的方式会强制在您每次进行调用时重新创建分配。如果你的最小和最大参数是固定的,那么创建一个分布对象并调用它,否则,保持你所拥有的。

顺便说一句,我会使用time(NULL) 或其他种子方法播种rnd

【讨论】:

  • time 是一个臭名昭著的坏种子,因为它具有确定性和典型的 1 秒粒度。打个电话std::random_device{}() 就更可取了。
【解决方案2】:

我怀疑分发对象的创建和销毁成本很高,尽管我认为它可能不仅仅是存储参数min,max。它可能会根据参数预先计算一些有用的值,例如在明显的实现中2**32 % (max-min+1) 是生成器中将被丢弃和重试的不同值的数量。

原则上,分发对象可以在其中存储一些熵位,这些熵位是在先前调用 operator() 时从生成器中提取的,但不是必需的。这些位可用于以后的operator() 调用。因此,如果min==0max==1,那么您可以在生成器上的每次调用中获得对operator() 的32 次调用。这就是 reset() 函数的作用,清除这个状态。

因此,如果您重复使用相同的最小/最大值,那么从技术上讲,您每次都使用新的分布会浪费随机位 - 与保留分布对象相比,您最终可能会减少对引擎的调用大约。但我怀疑它是否重要,尤其是因为 MT 很快。

【讨论】:

  • 呵呵,是的,主要是我的想法,但很高兴听到别人说。
  • 顺便说一句,不确定(没有检查),但如果这个类无论如何都是标题,我希望它可能根本没有开销,因为它会全部内联。跨度>
  • @Albert:我想取决于您对“无开销”的定义。即使 con/destructor 是内联的,它们仍然必须实际执行。您可以想象,某些发行版需要根据参数进行复杂的设置过程才能使用,只是uniform_int_distribution 显然不需要。
  • 查看此讨论:stackoverflow.com/a/14858040/259795,其中建议不断重置分布对象(类似于重新创建它)可能会影响生成数字的分布,具体取决于它的实现方式。
【解决方案3】:

熵存储在std::mt19937 中,这意味着您将继续随机序列,但正如 Steve Jessop 所指出的,它仍然有一些创建对象的开销。如果您希望使用相同的参数频繁调用此函数,则可以将 std::uniform_int_distribution&lt;uint32_t&gt; 对象缓存在使用 std::pair&lt;uint32_t, uint32_t&gt; 作为键的映射中。

【讨论】:

  • 我希望这种使用地图的方法实际上开销更大。 :)
  • 我同意这里。然后你只需要遵循 codewiz51 的建议。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-12-21
  • 1970-01-01
  • 2019-02-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-02
  • 1970-01-01
相关资源
最近更新 更多