std::seed_seq::generate

来自cppreference.com
< cpp‎ | numeric‎ | random‎ | seed seq
 
 
 
 
 
template<class RandomIt >
void generate( RandomIt begin, RandomIt end );
(C++11 起)

基于 v 中存储的(可能有偏差的)种子,通过以 32 位无符号整数值填充范围 [beginend) 的方式生成无偏差种子。

  • 如果 begin == endtrue,那么什么也不做。
  • 否则,按照如下所述的生成算法生成种子。

如果 std::iterator_traits<RandomIt>::value_type 不是无符号整数类型,或者它的宽度小于 32,那么程序非良构。

如果 RandomIt 不满足老式随机访问迭代器(LegacyRandomAccessIterator) 的要求,或者它不可变,那么行为未定义。

目录

[编辑]生成算法

给定以下值和操作:

定义
zv .size()
nend - begin
mstd::max(z +1, n)
t(n >=623)?11:(n >=68)?7:(n >=39)?5:(n >=7)?3:(n -1)/2
p(n - t)/2
qp + t
操作 定义
xor 内建的逐位异或
rshift 内建的向右移位
T(x)x xor (x rshift 27)

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

1) 将输出范围中的所有元素都设置为 0x8b8b8b8b
2)[0m) 中的所有整数 k,依次按顺序进行以下操作:
1)r11664525·T(Sk xor Sk+p xor Sk-1)
2)r2r1+j,其中 j 是:
  • z,如果 k=0
  • (k mod n)+Vk-1,如果 0<k⩽z
  • k mod n,如果 z<k
3)Sk+p 设置为 (Sk+p+r1) mod 232
4)Sk+q 设置为 (Sk+q+r2) mod 232
5)Sk 设置为 r2 mod 232
3)[mm + n) 中的所有整数 k,依次按顺序进行以下操作:
1)r31566083941·T(Sk+Sk+p+Sk-1)
2)r4r3-(k mod n)
3)Sk+p 设置为 (Sk+p xor r3) mod 232
4)Sk+q 设置为 (Sk+q xor r4) mod 232
5)Sk 设置为 r4 mod 232

[编辑]参数

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

[编辑]异常

只会抛出在 beginend 上的 RandomIt 操作抛出的异常。

[编辑]示例

#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//conststd::uint32_t n = last - first;conststd::uint32_t s = v.size();conststd::uint32_t t =(n <7)?(n -1)/2:(n <39)?3:(n <68)?5:(n <623)?7:11;conststd::uint32_t p =(n - t)/2;conststd::uint32_t q = p + t;conststd::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] 按 modulo 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, 1772877958, 2669970405, 3182737656, 4094066935}//// r1 = 423054846, 46783064, 3904109085, 1534123446, 1495905687// r2 = 423054841, 46783058, 3904109078, 1534123438, 1495905678//// seeds = { 4204997637, 4246533866, 1856049002, 1129615051, 690460811,// 1075771511, 46783058, 3904109078, 1534123438, 1495905678}//for(std::uint32_t k = m, r3, r4; k < m + n;++k){ r3 =1566083941* T(begin_mod(k)+ begin_mod(k + p)+ begin_mod(k -1)); r4 = r3 - k % n; begin_mod(k+p)^= r3; begin_mod(k+q)^= r4; begin_mod(k)= r4;}}};   int main(){constauto input =std::initializer_list<std::uint32_t>{1, 2, 3, 4, 5};constauto output_size =10;   // 使用 std 版本的 seed_seqstd::seed_seq seq(input);std::vector<std::uint32_t> seeds(output_size); seq.generate(seeds.begin(), seeds.end());for(conststd::uint32_t n : seeds)std::cout<< n <<'\n';   // 使用自定义版本的 seed_seq seed_seq seq2(input);std::vector<std::uint32_t> seeds2(output_size); seq2.generate(seeds2.begin(), seeds2.end());   assert(seeds == seeds2);}

输出:

4204997637 4246533866 1856049002 1129615051 690460811 1075771511 46783058 3904109078 1534123438 1495905678

[编辑]缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

缺陷报告 应用于 出版时的行为 正确行为
LWG 2180 C++11 seed_seq::generate 不会抛出异常 它可以抛出异常
close