全局随机数
本节阅读量:如果想在多个函数或文件中使用随机数生成器,会发生什么情况?一种方法是在main()函数中创建(并播种)PRNG,然后将其传递到需要它的任何地方。但可能这只偶尔使用的东西,但却有大量的传递。并且在许多不同的地方,传递这样的对象会给代码增加许多混乱。
或者,您可以在每个需要它的函数中创建静态局部std::mt19937变量(静态变量,以便它只被播种一次)。然而,让每个使用随机数生成器的函数定义并播种其自己的本地生成器是多余的,并且对每个生成器的调用量较低,也可能会导致质量较低的结果。
我们真正想要的是一个单一的PRNG对象,可以在任何地方共享和访问,跨越所有函数和文件。这里的最佳选项是创建全局随机数生成器对象。还记得我们是如何告诉您避免非常量全局变量的吗?这是一个例外。
下面是一个简单的、仅含头文件的解决方案,您可以将其包含在任何使用全局随机数的文件中:
random.h:
|
|
以及如何使用它的示例程序:
主.cpp:
|
|
通常,当头文件包含在多个源文件中时,在头文件中定义变量和函数将导致违反单定义规则(ODR)。然而,这里已经将mt变量和对应函数声明为inline,这允许在不违反ODR的情况下具有重复的定义,只要这些定义都相同。因为使用的#include 来引入头文件(而不是手动键入它们,或复制/粘贴它们),所以可以确保它们是相同的。
我们必须克服的另一个挑战是如何初始化全局Random::mt对象,因为我们希望它是自播种的,以便不必记住显式调用初始化函数。初始值设定项必须是表达式。为了初始化std::mt19937,需要几个辅助对象(std:∶random_device和std::seed_seq),这些对象必须定义为语句。这就是辅助函数派上用场的地方。函数调用是表达式,因此可以使用函数的返回值作为初始值设定项。在函数中,可以有需要的任何语句组合。因此,generate()函数创建并返回一个完全种子化的std::mt19937对象(使用系统时钟和std::random_device种子化),用作全局random::mt对象的初始值设定项。
一旦引用“Random.h”,可以用两种方法之一使用它:
- 可以调用Random::get()在两个值之间生成一个随机数(前闭后闭)。
- 可以通过Random::mt直接访问std::mt19937对象,并对其执行任何操作。
