C++ std::ranlux48_base 函数

2025年3月24日 | 阅读 9 分钟

伪随机数生成器 (PRNG) 主要用于需要伪随机源的模拟、恐吓、加密和统计研究。C 标准库中有许多用于生成随机数的工具,所有这些工具都可以在 <random> 库中找到。这些工具实际上并非随机。它们是伪随机或确定性工具,可生成一系列看似随机的数字,但如果使用相同的起始 (种子) 值,则会再次生成相同的序列。

这种确定性行为是 PRNG 的固有特性——PRNG 接收一个称为“种子”的初始值,并应用数学公式来生成一系列数字。然而,它看起来是随机的。如果只有设计该序列的人和他们使用的种子是已知的,那么它是非常可预测的。这一特性使它们非常重要,尤其是在希望结果可重现的模拟和测试情况下。

  • PRNG 引擎在复杂性和生成的随机性方面各不相同。一些引擎,如 std::minstd_rand,是简单的 LCG,具有低质量的随机数,但速度很快。另一些,如 Mersenne Twister,则更通用,质量更高,并且具有更长的周期长度,这在需要更高质量随机性的情况下很有用。但根据应用的不同,各种引擎在速度和随机数质量方面都存在问题。因此,PRNG 的选择取决于最佳的权衡选择。
  • 本文解释了需要不同类型的 PRNG,因为应用程序有不同的需求和期望。在一些情况下,速度比高质量随机数更重要,例如在基本的模拟和游戏中或简单的 蒙特卡罗模拟 中,而在其他情况下,随机数生成器的质量是最关键的因素,例如在 密码学 或非常高精度的蒙特卡罗模拟中。这就是 std::ranlux48_base 等更高级的生成器发挥作用的地方,它们旨在在考虑某些用途的性能的同时提供高质量的随机数。

什么是 std::ranlux48_base

std::ranlux48_base 是 C++ 标准库中可用的 PRNG 引擎之一,它的设计用于在生成随机数所需的计算时间量与产生的随机数的实际质量之间需要取得平衡的情况下使用。它属于 RANLUX 系列随机数生成器,该系列被认为可以生成高质量的随机序列,因为它们会拒绝一些由线性同余引擎或生成器产生的“非随机”数字。

  • RANLUX 系列最初由 Martin Lüscher 为需要非常高质量随机数生成器的科学计算而设计,特别是用于晶格量子色动力学 (LQCD)。RANLUX 生成器的主要思想是,并非所有由简单 LCG 生成的数字都足够随机,无法满足高度不可重现的应用。然而,为了使序列看起来更随机,RANLUX 会跳过或省略其序列中的一些数字,从而使随机数更好。
  • std::ranlux48_base 是此引擎系列中的一个特定引擎。更有趣的是,它采用了 48 位线性同余引擎,这意味着它具有 48 位的中间数据,并且操作的整数长度最多为 48 位。
  • 这使得它比 std::minstd_rand0 (使用 31 位状态) 等更简单的 LCG 引擎更强大,但速度也更慢。然而,如上所述,std::ranlux48_base 不会从其遵循的序列中省略任何数字。
  • 它是更豪华的 std::ranlux48 所派生的“base”引擎。虽然 std::ranlux48 会跳过值并且随机性更强,但 std::ranlux48_base 使用 LCG 算法生成随机数,其随机性略低于前一个,但生成速度更快。

std::ranlux48_base 的属性

std::ranlux48_base 是一个线性同余生成器 (LCG),并使用 48 位状态执行其计算。它使用以下公式生成随机数:

  • 该生成器使用几个常数进行工作,例如 x_n 是序列中的当前数字。然而,引擎包含 2^48,因此序列会为 succession 中的 2^48 个数字而重复。
  • ranlux48_base 的相对优势的关键特性之一是它的随机性比几乎所有其他序列都快。
  • 与更先进的 std::ranlux48 不同,后者会丢弃一些数字以提高随机性,std::ranlux48_base 不会丢弃任何数字,这使其速度更快,但随机数质量略低。
  • 这种效率使其适用于性能至关重要但不需要极高随机数质量的应用,包括游戏模拟和简单的科学计算。它在 <random> 头文件中声明,并且是 std 命名空间的一部分。

std::ranlux48_base 的用例

std::ranlux48_base 是 C++ 中的一个 PRNG,专为在性能和随机数质量之间的平衡至关重要但又很复杂的情况下设计。以下是一些 std::ranlux48_base 的常见用例:

  • 模拟和蒙特卡罗方法: PRNG 用于在科学和统计模拟中对随机过程进行建模;如果不需要非常高质量的随机输出,std::ranlux48_base 可提供中等质量的随机数和相对良好的计算性能。选择 2^48 的较长周期可以保证后续数字在相当长一段时间内不会重复,因此非常适合中等规模的模拟。
  • 游戏开发: 在游戏开发中,随机数可以用于选择关卡元素、事件或洗牌数组。由于 std::ranlux48_base 比 std:ranlux48 等更复杂的生成器更快,但它能产生良好的随机性,因此非常适合对性能要求高于密码学安全随机生成器的游戏应用。
  • 统计抽样: 如果随机性质量不必很高,并且 std::ranlux48_base 是合适的类别,那么中等优先级的工作,例如数据分析中的简单随机抽样或其他统计技术,就非常适合。当数据流庞大且操作速度至关重要时,这可能很有用。
  • 非关键性模拟: 由于有时可能需要 PRNG 进行不需要高质量随机性的模拟,例如基本的物理模拟或算法测试,那么 std::ranlux48_base 就相当高效。

为 std::ranlux48_base 中的引擎播种

  • 播种是处理 std::ranlux48_base 等伪随机数生成器 (PRNG) 的关键方面,因为它分配了随机数生成器引擎产生的随机数序列的第一个几个数字或种子。
  • 与确定性 PRNG 一样,PRNG 生成的数字并非随机,而是基于底层数学算法。这意味着如果将相同的种子输入到引擎中,则该数字序列的输出将始终相同,这在模拟或 调试 等情况下至关重要。
  • 种子的概念可能仅限于特定上下文,特别是根据本工作的观点,“引擎的初始状态”。通常,引擎会使用系统时钟或其他随机源的值进行初始化。但在后一种情况下,您可以指定一个自定义种子来控制输出序列。对于 std::ranlux48_base,这是通过 seed() 函数完成的,该函数可以接受整数或另一个随机源。例如:

这意味着每次执行程序并将种子值设置为 12345 时,引擎将产生完全相同的随机数序列。此属性在测试或调试应用程序时特别有用,因为它允许我们模拟代码中的确切条件和行为。

如果未提供种子,引擎将设置一个种子,大概是利用当前时间,这样如果再次运行程序,将产生不同的序列。如果您希望在程序运行时获得不同级别的随机性,但又不关心可靠性,这会很有帮助。

编码

输出

 
First 10 random numbers generated by std::ranlux48_base: 
30624511805803 114996294343928 79930194652383 62531497946618 129771911128749 106231211407048 79885003037325 91355970505878 127270706838653 49703586973510  
  
Random floating-point numbers in the range [0, 1): 
0.6971 0.2864 0.5393 0.7613 0.8032 0.8181 0.4842 0.4142 0.5480 0.8320  
  
Random integers in the range [0, 99]: 
55 69 38 80 76 74 96 41 87 95  
  
Simulating 10 dice rolls: 
3 1 2 4 4 6 5 6 6 6  
  
Original vector: 
1 2 3 4 5 6 7 8 9 10  
Shuffled vector: 
10 3 5 7 1 8 4 6 9 2  
  
Random sampling from a set of elements (choosing 5 from {0, 1, ..., 19}): 
1 16 10 12 15  
  
Demonstrating repeating sequences: 
First 10 random numbers from engine2 (same seed): 
30624511805803 114996294343928 79930194652383 62531497946618 129771911128749 106231211407048 79885003037325 91355970505878 127270706838653 49703586973510  
Next 5 numbers from Engine: 
18762030123288 147186257781979 140059358354656 119221270255519 87628723186538  
Next 5 numbers from engine2: 
18762030123288 147186257781979 140059358354656 119221270255519 87628723186538  
  
First 10 random numbers from engine3 (different seed): 
133031433434303 7756433787978 39967638941832 189279895723317 167530702842012 76040823056437 71929229911424 10764313819113 23441916049750 37862276864627    

结论

总之,std::ranlux48_base 是 C++ 中一个不错的 PRNG 引擎选择,它在计算速度和随机性之间实现了相当好的比例。与许多其他引擎一样,它使用 48 位线性同余生成器 (LCG) 作为基础,这仍然是一个纯粹的确定性伪随机数生成器,即,当输入相同的种子值时,它会重复相同的数字序列。此属性使其适用于模拟环境开发、游戏开发和统计学等领域,在这些领域,速度和中等程度的随机性被认为很重要。

ranlux48_base 的关键特性是它比包括 std::ranlux48 在内的许多引擎更简单,同时能产生更好的结果。它不会从其系列中排除任何数字,因此速度更快,但随机性会略有牺牲。然而,对于不太敏感的应用,如果不需要实现特定目标,这种随机性水平通常就足够了。

播种在控制 std::ranlux48_base 的输出方面起着至关重要的作用,这使得重复模拟或测试成为可能。此外,通过设置种子,开发人员可以获得相同的随机数序列,这有助于调试并确保程序每次执行时都运行相同。

std::ranlux48_base 是一个快速而有用的选项,适用于所有需要平衡随机数生成速度和数字随机性的应用程序,这使得 ranlux48_base 成为 C++ 中随机数生成工具集合的有价值的补充。