std::seed_seq::generate
来自cppreference.com
| |
(C++11 起) | |
基于 v 中存储的(可能有偏差的)种子,通过以 32 位无符号整数值填充范围 [begin, end) 的方式生成无偏差种子。
- 如果
begin == end是true,那么什么也不做。 - 否则,按照如下所述的生成算法生成种子。
如果 std::iterator_traits<RandomIt>::value_type 不是无符号整数类型,或者它的宽度小于 32,那么程序非良构。
如果 RandomIt 不满足老式随机访问迭代器 (LegacyRandomAccessIterator) 的要求,或者它不可变,那么行为未定义。
生成算法
给定以下值和操作:
| 值 | 定义 |
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) |
生成算法包含以下步骤,其中 Si 表示 begin[i % n],Vi 表示 v [i]:
1) 将输出范围中的所有元素都设置为
0x8b8b8b8b。2) 对
[0, m) 中的所有整数 k,依次按顺序进行以下操作:1) 设 r1 为 1664525·T(Sk xor Sk+p xor Sk-1)。
2) 设 r2 为 r1+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) 对
[m, m + n) 中的所有整数 k,依次按顺序进行以下操作:1) 设 r3 为 1566083941·T(Sk+Sk+p+Sk-1)。
2) 设 r4 为 r3-(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 | - | 表示输出范围的迭代器 |
异常
只会抛出在 begin 和 end 上的 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
//
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] 按 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()
{
const auto input = std::initializer_list<std::uint32_t>{1, 2, 3, 4, 5};
const auto output_size = 10;
// 使用 std 版本的 seed_seq
std::seed_seq seq(input);
std::vector<std::uint32_t> seeds(output_size);
seq.generate(seeds.begin(), seeds.end());
for (const std::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 不会抛出异常
|
它可以抛出异常 |