我使用以下代码在 C++ 中生成随机数
std::random_device rdev {};
std::default_random_engine generator {rdev()};
std::uniform_int_distribution dist {a, b};
Run Code Online (Sandbox Code Playgroud)
相似地
std::default_random_engine generator {std::random_device{}()};
std::uniform_int_distribution dist {a, b};
Run Code Online (Sandbox Code Playgroud)
我想了解的是使用种子值生成引擎背后的机制。random_device 使用来自操作系统的各种信息获取种子。该值用于初始化引擎对象。对于此处介绍的第一段代码,如果rdev是一个对象,为什么我们将该值作为rdev(). 为什么我们在类的对象上使用函数符号?
对于第二段代码,我们如何std::random_device仅使用类名来生成对象?
我不确定我在理解这方面的问题是否特定于随机数生成或涉及 C++ 语言本身的更大问题。
所述std::random_device对象本身不被用作种子。Arandom_device是真随机数生成器。调用它的括号运算符会从中产生一个样本。不幸的是,生成真随机数往往比生成伪随机数更昂贵,因此作为一种折衷方案,人们倾向于生成一个真正的随机数作为种子传递给伪随机生成器。因此,在您的第一个示例中,random_device通过调用其括号运算符 ( rdev())对 进行了一次采样,返回一个真正随机的值,该值用作std::default_random_engine对象的种子。
第二个示例完全相同,只是在这种情况下random_device是临时的。在 C++ 中,您可以通过直接调用类的构造函数来构造临时对象,在这种情况下使用大括号初始化。换句话说,表达式std::random_device{}返回一个临时的、默认构造的random_device对象,然后像前面的例子一样调用它的括号运算符来产生一个种子。
std::random_device重载括号运算符以赋予其类似函数的语法。它或多或少看起来像这样:
class random_device {
/*...*/
public:
uint32_t operator()() {
return /*...*/;
}
};
Run Code Online (Sandbox Code Playgroud)
然后可以在对象上调用它
std::random_device device;
uint32_t value = device();
Run Code Online (Sandbox Code Playgroud)
或临时的(技术上仍然是一个对象)
uint32_t value = std::random_device{}();
uint32_t value_2 = std::random_device()(); //Equivalent syntax
Run Code Online (Sandbox Code Playgroud)
超载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
Run Code Online (Sandbox Code Playgroud)