【问题标题】:Using random number generator: multiple instances or singleton approach?使用随机数生成器:多实例还是单例方法?
【发布时间】:2014-10-11 04:27:17
【问题描述】:

我创建了一个类,我可以将其用作比标准 rand() 更好的随机数生成器。下面我为我的类包含了 .cpp 文件,其中包含类变量 std::mt19937 gen 和 std::uniform_real_distribution distr。

我的问题是是否有必要创建我的号码生成器的多个实例。例如,如果我有 A 类和 B 类,并且每个类都需要在 [0,1] 范围内采样随机数,如果 A 和 B 都有自己的 UniformNumberGenerator 实例会更好,或者我应该采用单例方法并使用两个类的一个实例?

UniformNumberGenerator::UniformNumberGenerator(double min, double max)
{
    gen = CreateGenerator();
    distr = std::uniform_real_distribution<double>(min, max);
}

std::mt19937 UniformNumberGenerator::CreateGenerator()
{
    std::random_device rd;
    std::mt19937 result(rd());
    return result;
}

//Take a sample
double UniformNumberGenerator::operator()()
{
    return distr(gen);
}

【问题讨论】:

  • 这似乎毫无意义。标准库已经将随机性和分布因素精确地考虑到了应该在功能上保持独立的两个组件中:一个昂贵的 engine 生成一次(每个线程)并且永远不会再被触及,和廉价的 distribution 对象,它们根据给定的随机源产生实际数字。你在重新发明轮子,只是你的轮子有角并且是用纸糊做的。
  • 您如何启动/播种您的发电机?大多数随机生成器允许种子值,它允许可重复的序列以及“随机”。如果你这样做,单例会更好。
  • 我在“CreateGenerator”方法中为生成器播种。 mt19937 实例使用 std::random_device rd 播种。 @KerrekSB 当你说这两个组件应该分开时,你能解释一下吗?您需要为分布提供一个随机生成器,以使其产生一个值。

标签: c++ class random singleton instance


【解决方案1】:

拥有多个伪随机数生成器 (PRNG) 实例的一个正当理由是,使用相关归纳策略提高两个系统之间差异的模拟估计精度。其中最简单的是“common random numbers”(CRN)*。直观地说,如果您的银行或杂货店有两种不同的安排,并且您想确定哪种配置效果最好,那么将它们与完全相同的一组客户和交易进行比较是有意义的。 CRN 通过为两种场景生成完全相同的 PRN 序列来做到这一点,但您必须非常小心以保持 PRNG 流同步。如果两个系统具有不同数量的永久实体(例如服务器),这可能是一个真正的挑战。在这种情况下,每个服务器一个 PRNG 是合适的,一个 PRNG 也可以为每个到达流生成特征。所有 PRNG 将在一次运行中独立播种(因此服务器看起来彼此独立),并且在运行之间进行相同的播种以产生运行级同步。

底线 - 除非您计划使用相关归纳策略来减少方差,并且您确实确定自己知道自己在做什么,否则您应该使用单个 PRNG。 MT19937 为相当大的 k 值生成顺序不相关的 k 元组,如果我没记错的话,超过 600。如果您的目标是生成独立样本,那么这正是 MT19937 和其他体面的生成器旨在通过生成器的单个实例模拟的内容。

* - Wikipedia 上也有一篇关于此的文章,但目前写得非常糟糕,因此我不建议将其用作资源。

【讨论】:

  • 当你说它产生“对于相当大的 k 值,超过 600 的顺序不相关的 k 元组”是否意味着在产生 600 个随机值之后模式会重复?我的程序总而言之需要产生可能数十万甚至数百万的随机数。那么在这种情况下,单身人士会成为问题吗?
  • 不,mt19937 不会像您想的那样重复。 mt19937 将重复单个值 - 这很好,因为它是真正随机性的行为方式 - 但在您绘制 219937-1 个值之前它不会重复序列。这将需要运行比当前宇宙生命大许多数量级的时间。有关 k 分布属性的正式定义,请参见 Wikipedia article。真的,这不是问题,我什至不应该提出来。
【解决方案2】:

我无法根据您发布的代码来判断您的随机数生成器,但我可以根据哪种方法(实例化生成器的一些副本与使用单个全局生成器)最好说几句话:

  1. 如果内存很重要,显然单例方法是您更喜欢的方法,因为您只分配一次内存
  2. 除非您的生成器支持您希望用于对象的任何奇特功能,例如能够在特定的、可自定义的分布中生成数字,否则我真的看不出有理由在其中包含多个此生成器的实例应用程序。
  3. 如果我想到您通常如何在应用程序中使用随机数生成器 - 您很少需要调用它 - 我会选择单例方法。

希望这会有所帮助...

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-09-23
    • 1970-01-01
    • 2020-06-29
    • 1970-01-01
    • 1970-01-01
    • 2014-06-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多