Namespaces
Variants

std::seed_seq:: generate

From cppreference.net
template < class RandomIt >
void generate ( RandomIt begin, RandomIt end ) ;
(自 C++11 起)

通过基于存储在 v 中的(可能存在偏差的)种子,向输出范围 [ begin , end ) 填充32位无符号整数值来生成无偏种子。

  • 如果 begin == end true ,则不执行任何操作。
  • 否则,通过下文描述的生成算法生成种子。

如果 std:: iterator_traits < RandomIt > :: value_type 不是无符号整数类型,或其宽度小于32位,则程序非良构。

如果 RandomIt 不满足 LegacyRandomAccessIterator 的要求,或者它不是 mutable 的,则行为未定义。

目录

生成算法

给定以下数值与运算:

定义
z v  . size ( )
n end - begin
m std:: max ( z + 1 , n )
t ( n >= 623 ) ? 11 : ( n >= 68 ) ? 7 : ( n >= 39 ) ? 5 : ( n >= 7 ) ? 3 : ( n - 1 ) / 2
p ( n - t ) / 2
q p + t
操作 定义
xor 内置 按位异或
rshift 内置 按位右移
T(x) x xor (x rshift 27)

生成算法包含以下步骤,其中 S i 表示 begin [ i % n ] V i 表示 v  [ i ]

1) 将输出范围的每个元素设置为值 0x8b8b8b8b
2) 对于区间 [ 0 , m ) 内的每个整数 k ,按顺序执行以下操作:
1) r 1 1664525·T(S k xor S k+p xor S k-1 )
2) r 2 r 1 +j ,其中 j 满足:
  • z ,若 k=0
  • (k mod n)+V k-1 ,若 0<k⩽z
  • k mod n ,若 z<k
3) S k+p 设置为 (S k+p +r 1 ) mod 2 32
4) 设置 S k+q (S k+q +r 2 ) mod 2 32
5) S k 设置为 r 2 mod 2 32
3) 对区间 [ m , m + n ) 内的每个整数 k ,按顺序执行以下操作:
1) r 3 1566083941·T(S k +S k+p +S k-1 )
2) r 4 r 3 -(k mod n)
3) S k+p 设为 (S k+p xor r 3 ) mod 2 32
4) S k+q 设为 (S k+q xor r 4 ) mod 2 32
5) S k 设置为 r 4 mod 2 32

参数

begin, end - 表示输出范围的迭代器

异常

仅抛出对 begin end 进行 RandomIt 操作时抛出的异常。

注释

生成算法改编自 松本真和西村拓士 提出的梅森旋转生成器初始化序列,并融合了 斋藤睦夫于2007年 实现的改进方案。

示例

#include <algorithm>
#include <cassert>
#include <cstdint>
#include <iostream>
#include <random>
// 对 std::seed_seq 主要部分进行原型设计...
struct seed_seq
{
    std::vector<std::uint32_t> v;
    seed_seq(std::initializer_list<std::uint32_t> const il) : v{il} {}
    template<typename RandomIt>
    void generate(RandomIt first, RandomIt last)
    {
        if (first == last)
            return;
        //
        // 假设 v = {1, 2, 3, 4, 5} 且 distance(first, last) == 10。
        //
        // 步骤 1:填充 0x8b8b8b8b
        // seeds = {2341178251, 2341178251, 2341178251, 2341178251, 2341178251,
        //          2341178251, 2341178251, 2341178251, 2341178251, 2341178251}
        //
        std::fill(first, last, 0x8b8b8b8b);
        //
        // 步骤 2:
        // n = 10, s = 5, t = 3, p = 3, q = 6, m = 10
        //
        const std::uint32_t n = last - first;
        const std::uint32_t s = v.size();
        const std::uint32_t t = (n < 7) ? (n - 1) / 2
                              : (n < 39) ? 3
                              : (n < 68) ? 5
                              : (n < 623) ? 7
                              : 11;
        const std::uint32_t p = (n - t) / 2;
        const std::uint32_t q = p + t;
        const std::uint32_t m = std::max(s + 1, n);
        //
        // 第一次迭代,k = 0;r1 = 1371501266,r2 = 1371501271
        //
        // seeds = {1371501271, 2341178251, 2341178251, 3712679517, 2341178251,
        //          2341178251, 3712679522, 2341178251, 2341178251, 2341178251}
        //
        // 迭代从 k = 1 到 k = 5(r2 = r1 + k % n + v[k - 1])
        //
        // r1 = 2786190137, 3204727651, 4173325571, 1979226628, 401983366
        // r2 = 2786190139, 3204727655, 4173325577, 1979226636, 401983376
        //
        // seeds = {3350727907, 3188173515, 3204727655, 4173325577, 1979226636,
        //           401983376, 3591037797, 2811627722, 1652921976, 2219536532}
        //
        // 迭代从 k = 6 到 k = 9(r2 = r1 + k % n)
        //
        // r1 = 2718637909, 1378394210, 2297813071, 1608643617
        // r2 = 2718637915, 1378394217, 2297813079, 1608643626
        //
        // seeds = { 434154821, 1191019290, 3237041891, 1256752498, 4277039715,
        //          2010627002, 2718637915, 1378394217, 2297813079, 1608643626}
        //
        auto begin_mod = [first, n](std::uint32_t u) -> decltype(*first)&
        {
            return first[u % n]; // 即 begin[x] 取模 n
        };
        auto T = [](std::uint32_t x) { return x ^ (x >> 27); };
        for (std::uint32_t k = 0, r1, r2; k < m; ++k)
        {
            r1 = 1664525 * T(begin_mod(k) ^ begin_mod(k + p) ^ begin_mod(k - 1));
            r2 = (k == 0) ? r1 + s
               : (k <= s) ? r1 + k % n + v[k - 1]
               :            r1 + k % n;
            begin_mod(k + p) += r1;
            begin_mod(k + q) += r2;
            begin_mod(k) = r2;
        }
        //
        // 步骤 3
        // 迭代从 k = 10 到 k = 19,使用 ^= 修改输出
        //
        // r1 = 1615303485, 3210438310, 893477041, 2884072672, 1918321961,
        // r2 = 1615303485, 3210438309, 893477039, 2884072669, 1918321957
        //
        // seeds = { 303093272, 3210438309,  893477039, 2884072669, 1918321957,
        //          1117182731

缺陷报告

以下行为变更缺陷报告被追溯应用于先前发布的C++标准。

缺陷报告 适用范围 发布时行为 正确行为
LWG 2180 C++11 seed_seq::generate 不抛出异常 可能抛出异常