【问题标题】:Where to initialize random seed for use through multiple random modules?在哪里初始化随机种子以通过多个随机模块使用?
【发布时间】:2012-05-25 09:00:18
【问题描述】:

所以,每次我在开发一些大的东西时,将多个模块组合在一起构建最终功能,我一直在想同一个问题:如果超过 1 个模块需要使用随机函数,那么在哪里初始化随机种子?

如果我有一个需要随机的类(例如,通过使用自我实现的快速排序对输入数组进行排序来初始化自身的类,所以我需要一个随机的枢轴选择),我通常有一个私有的 static bool isRandOn; 变量,所以在我开始随机枢轴选择之前,我会检查该变量,如果随机还没有打开,则执行srand(time(NULL));

如果我在命名空间中有大量实用程序函数,我会做类似的事情:我将这样一个变量放在我的 utils 库中的匿名命名空间中,并与类做或多或少相同的事情.

我遇到的问题是在组合这些模块时。就其本身而言,我知道每个模块不会多次设置种子。但是,我希望能够同时使用不同数量的模块,我希望其他人能够独立于其他人使用我的一个或多个模块...

那么,处理多个需要随机种子的模块的最佳方法是什么?在每个模块中设置种子?根本不设置种子,而是记录随机的用法并让用户在他想使用模块时初始化种子?第三个?

【问题讨论】:

  • 多次设置种子有什么问题?
  • 我不知道,这就是我问的原因:) 如果在整个执行过程中有效地重置种子几次,它不会降低整个事情的随机性吗?
  • 假设您每次都使用 time(NULL),并且无法真正预测 time() 将返回什么,我看不出一个随机数会如何更随机比下一个。
  • 我猜我在问什么,你是在代码中间的某个地方调用 srand,还是有多个类在一开始就都调用它?如果你一开始就有 5 次调用,然后一直使用同一个种子,那也没关系......
  • 因为我在多个项目中都想知道这一点,其中一些在运行时偶尔调用种子,其中一些只是在开始时,我想知道整体的最佳实践。跨度>

标签: c++ random srand


【解决方案1】:

我建议使用 Boost.Random 而不是依赖于在程序级别共享的某些全局状态。

Boost.Random 有两个概念:

  • 引擎:生成随机数
  • 分布:调整引擎的结果以提供适合特定分布(正态、泊松、高斯等)的结果

然后每个模块可能有自己的引擎,或者实际上是其中的几个:没有特定理由让同一模块内的几个不同功能共享给定引擎。

最后一句话:无论您做什么,请确保您有办法确定性地设置种子以用于错误重现。错误重现可能会受益于拥有多个引擎(部件隔离有帮助)。

【讨论】:

  • 我知道用于调试的确定性种子。几年前才了解到这一点:) 这是一个很好的建议,但由于我正在寻找适用于各种情况的最佳实践,所以对于何时不允许使用像 Boost 这样的外部库有什么建议吗? (或者,如果在团队中开发,至少是团队外的库?)
  • @penelope:嗯,重新开发相同的概念? mersenne twister 通常很容易实现,您可以直接使用结果(它类似于rand() 将生成的结果)。当你真的想要 [89, 99) 中的整数时,Boost 中的分布只是糖衣,比rand() % 10 + 89 具有更有意义的语法。当然,他们不会引入偏见(与我的快速演示相反)。
【解决方案2】:

您可以为随机数生成创建一个特殊的“模块”,并在应用程序的其他部分使用它。然后在初始化随机数模块时只播种一次。

【讨论】:

  • 只有在以下情况下才有效:a)我是唯一一个使用和开发我的应用程序的人,b)没有其他人会使用我的任何单独的模块,c)它不会与外部的任何东西混合。我想知道尽可能广泛适用的最佳做法是什么。
【解决方案3】:

@penelope 给出了正确答案。 rand() 后面有一些复杂的生成伪随机数序列的算法。这就像某个函数rand_func(prev_rand),它从前一个生成下一个伪随机数。您第一次调用srand(time(NULL)),在这些术语中将prev_rand 设置为假设time(NULL) 非常不确定。因此,您可以安全地多次调用srand()(设置 )。

特殊问题是您是否需要 可预测 伪随机序列:例如,srand(0) 等。但这似乎不是您的情况。

【讨论】:

    【解决方案4】:

    我想避免总是重复相同的初始随机序列的最佳方法是在调用 random() 函数的每个模块中执行以下操作:

    /* Global variable to remember if we already initialized the PRNG */
    static bool seed_initialized = false;
    
    /* Helper function to avoid having always the same sequence again and again */
    static void
    prng_init (unsigned int seed)
    {
      if (!seed_initialized)
        {
          srandom (seed);
          seed_initialized = true;
        }
    }
    

    而且,每次您在函数中使用 random() 时,都会以如下方式启动函数:

     /* Initializing PRNG with a 'reasonably strong' random seed for our purpose */
     prng_init (time (NULL) - getpid());
    

    这样,您可以确保:

    1. 您将至少在第一次通过时初始化您的 PRNG;

    2. 您永远不会在模块内多次重新初始化随机序列。

    希望对您有所帮助!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-03-05
      • 1970-01-01
      • 1970-01-01
      • 2021-07-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多