我使用以下代码在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 ++语言本身的更大问题。
答案 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