【问题标题】:Creating a function to return a random number in a specified range创建一个函数以返回指定范围内的随机数
【发布时间】:2015-12-14 13:20:56
【问题描述】:

我正在浏览 C++ Primer,我刚刚完成了讨论<random> 实用程序的章节。问我几个问题:

练习 17.28:编写一个函数,生成并返回一个统一的 每次调用时分发随机无符号整数。

练习 17.29:允许用户提供种子作为可选参数 你在上一个练习中编写的函数。

练习 17.30:这次再次修改你的函数,以最小化和 函数应返回的数字的最大值。

这些问题希望我使用讨论过的random_default_engineuniform_int_distribution 类。第一个问题很简单:

#include <random>
unsigned randomUns(){
    static default_random_engine e;
    static uniform_int_distribution<unsigned> u;
    return u(e);
}

使用创建对象static 的建议,这样它们就不会在调用后被销毁,因此每次调用函数都会生成一个新数字,而不是每次都从序列的开头开始。困难出在最后两个问题上,我原来的解决办法是:

unsigned randomUns(unsigned minV, unsigned maxV, default_random_engine::result_type seed = 0){
    static default_random_engine e(seed);
    static uniform_int_distribution<unsigned> u(minV, maxV);
    return u(e);
}

除了那是在我意识到静态变量只被初始化一次之前。所以这个函数将使用来自对randomUns 的调用的参数初始化u,然后再也不会。我只能在一个范围内使用此功能。例如

cout << randomUns(2,3) << " " << randomUns(5,6);

尽管第二个范围不同,但可能会输出 2 3

seed 也存在类似问题。我将如何处理这个?对于引擎/种子,我也许可以像这样重写函数:

static default_random_engine::result prev = 0;
static default_random_engine e(seed);
if(prev != seed){ 
    e.seed(seed)
    prev = seed;
}

但这当然不是一个真正的随机函数。

randomUns(1,2,50);
randomUns(1,2,60);
randomUns(1,2,50);

据我所知,第三次调用将产生与第一次相同的输出,因为引擎已重置回相同的状态。对于更改分布的范围,我完全不确定。

变量不能在每次调用后销毁,否则函数将始终输出相同的序列 - 所以它们必须是 static 或存在于函数范围之外。另一方面,我需要能够控制范围/种子,因此需要在函数内修改变量。

这可以通过random_default_engineuniform_int_distribution 提供的实用程序实现吗?

【问题讨论】:

  • 经过更好的研究后,似乎我可能不得不每次都回避创建新的发行版。 (See 和里面提供的所有链接)。 uniform_int_distribution 看起来不错,但对于其他发行版来说可能不是那么简单。所以我将按照 std::rand_replacement 中的建议方法,使用param_type 成员定义生成值的范围:See
  • 或者,如果希望为不同的范围生成不同的分布:See。当然可以更进一步并使用tuple 来确保相同的生成器用于相同的发行版,我不完全确定这是否有必要。

标签: c++ c++11 random


【解决方案1】:

保持引擎static,但分配非静态,例如

unsigned randomUns(unsigned minV, unsigned maxV, default_random_engine::result_type seed = 0){
    static default_random_engine e(seed);
    uniform_int_distribution<unsigned> u(minV, maxV);
    return u(e);
}

要允许每次调用都更改自定义种子,请也存储种子,如果不同,则重新创建引擎。

可能是这样的

unsigned randomUns(unsigned minV, unsigned maxV, default_random_engine::result_type seed = 0){
    static default_random_engine e(seed);
    static default_random_engine::result_type last_seed = seed;

    if (seed != last_seed){
        e = default_random_engine(seed);
        last_seed = seed;
    }

    uniform_int_distribution<unsigned> u(minV, maxV);
    return u(e);
}

【讨论】:

  • 我很好奇分布是否需要是静态的。我的消息来源说“做”,但没有真正解释原因:同样,分布可能会保留状态,也应该在循环之外定义。
  • @Silversonic 因为静态初始化只需要初始化一次。因此,每次重新初始化它通常会更快更干净。但是,如果您有动态输入,则不可能。所以基本上:如果你能做一些静态的东西(const),那就去做吧。
  • @Silversonic 同样在函数中声明一个静态局部变量大致转换为检查: if(!variableInitialized) { variable = initValue; }
  • @Neijwiert 好的。但我猜这仅适用于uniform_int_distributionSome answers in this SO question 建议重置其他分布类型的状态可能会破坏输出分布。
  • @Silversonic 在RNG 的情况下,这是正确的,是的。由于每次调用该函数时它都会重新初始化,因此它将为给定 min max 的每个种子返回相同的数字。您可以解决这个问题,并且仍然可以使用模板进行静态初始化。或者如果种子是动态创建的,您需要为RNG's 使用某种池
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-07-24
  • 2020-02-21
  • 2018-12-17
  • 2016-01-23
  • 2013-10-05
  • 2020-07-12
  • 1970-01-01
相关资源
最近更新 更多