使用std :: random_device

时间:2017-07-31 20:54:26

标签: c++ random

我使用以下代码在C ++中生成随机数

std::random_device rdev {};
std::default_random_engine generator {rdev()};
std::uniform_int_distribution dist {a, b};

类似地

std::default_random_engine generator {std::random_device{}()};
std::uniform_int_distribution dist {a, b};

我试图理解的是使用种子值生成引擎的机制。 random_device使用操作系统中的各种信息获取种子。该值用于初始化引擎对象。对于此处提供的第一段代码,如果rdev是一个对象,为什么我们将该值作为rdev()传递给引擎。为什么我们在类的对象上使用函数表示法?

对于第二段代码,我们如何通过使用类名来生成std::random_device对象?

我不确定我理解这个问题是否特定于随机数生成或涉及C ++语言本身的更大问题。

2 个答案:

答案 0 :(得分:3)

std::random_device对象本身不用作种子。 random_device是一个真随机数生成器。调用其括号运算符会从中生成一个样本。不幸的是,生成真随机数往往比生成伪随机数更昂贵,因此作为折衷方案,倾向于生成单个真正随机数作为种子传递给伪随机数。因此,在您的第一个示例中,通过调用其括号运算符(random_device)一次对rdev()进行采样,返回一个真正的随机值,该值用作std::default_random_engine对象的种子

第二个例子完全相同,只是在这种情况下random_device是临时的。在C ++中,您可以通过直接调用类的构造函数来构造临时函数,在本例中使用大括号初始化。换句话说,表达式std::random_device{}返回一个临时的,默认构造的random_device对象,然后调用其括号运算符,如上例所示,以生成种子。

答案 1 :(得分:3)

std::random_device重载括号运算符以赋予它类似函数的语法。它或多或少看起来像这样:

class random_device {
    /*...*/
public:
    uint32_t operator()() {
        return /*...*/;
    }
};

然后可以在对象上调用它

std::random_device device;
uint32_t value = device();

或临时(技术上仍然是对象)

uint32_t value = std::random_device{}();
uint32_t value_2 = std::random_device()(); //Equivalent syntax

operator()重载也可以通过其他方式重载。

struct multiplies_by_3 {
    uint32_t operator()(uint32_t value) const {
        return value * 3;
    }
};

multiplies_by_3 multiplier;
uint32_t value = multiplier(15); //45
uint32_t value_2 = multiplies_by_3{}(20); //60
uint32_t value_3 = multiplies_by_3()(25); //75

struct subtracts_first_from_second {
    uint32_t operator()(uint32_t first, uint32_t second) const {
        return second - first;
    }
};

subtracts_first_from_second subtractor;
uint32_t value = subtractor(15, 17); //2
uint32_t value_2 = subtracts_first_from_second{}(20, 29); //9
uint32_t value_3 = subtracts_first_from_second()(25, 17); //Underflows to some large number