std::seed_seq::generate
template< class RandomIt >
void generate( RandomIt begin, RandomIt end );
|
(since C++11) | |
Generate unbiased seeds by filling the output range [begin, end) with 32-bit unsigned integer values, based on the (possibly biased) seeds stored in v.
- If
begin == endistrue, does nothing. - Otherwise, generates seeds by the generation algorithm described below.
If std::iterator_traits<RandomIt>::value_type is not an unsigned integer type, or its width is less than 32, the program is ill-formed.
If RandomIt does not meet the requirements of LegacyRandomAccessIterator, or it is not mutable, the behavior is undefined.
Generation algorithm
Given the following values and operations:
| Value | Definition |
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
|
| Operation | Definition |
| xor | built-in bitwise XOR |
| rshift | built-in bitwise right-shift |
| T(x) | x xor (x rshift 27) |
The generation algorithm consists of the following steps, where Si denotes begin[i % n], Vi denotes v [i]:
0x8b8b8b8b.k in [0, m), performs the following operations in order:- z, if k=0
- (k mod n)+Vk-1, if 0<k⩽z
- k mod n, if z<k
.
.
.
k in [m, m + n), performs the following operations in order:.
.
.
Parameters
| begin, end | - | the iterators denoting the output range |
Exceptions
Only throws the exceptions thrown by the RandomIt operations on begin and end.
Notes
The generation algorithm is adapted from the initialization sequence of the Mersenne Twister generator by Makoto Matsumoto and Takuji Nishimura, incorporating the improvements made by Mutsuo Saito in 2007.
Example
#include <algorithm>
#include <cassert>
#include <cstdint>
#include <iostream>
#include <random>
// Prototyping the main part of 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;
//
// Assuming v = {1, 2, 3, 4, 5} and distance(first, last) == 10.
//
// Step 1: fill with 0x8b8b8b8b
// seeds = {2341178251, 2341178251, 2341178251, 2341178251, 2341178251,
// 2341178251, 2341178251, 2341178251, 2341178251, 2341178251}
//
std::fill(first, last, 0x8b8b8b8b);
//
// Step 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);
//
// First iteration, k = 0; r1 = 1371501266, r2 = 1371501271
//
// seeds = {1371501271, 2341178251, 2341178251, 3712679517, 2341178251,
// 2341178251, 3712679522, 2341178251, 2341178251, 2341178251}
//
// Iterations from k = 1 to 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}
//
// Iterations from k = 6 to 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]; // i.e. begin[x] is taken 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;
}
//
// Step 3
// iterations from k = 10 to k = 19, using ^= to modify the output
//
// 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;
// using std version of 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';
// using custom version of seed_seq
seed_seq seq2(input);
std::vector<std::uint32_t> seeds2(output_size);
seq2.generate(seeds2.begin(), seeds2.end());
assert(seeds == seeds2);
}
Output:
4204997637
4246533866
1856049002
1129615051
690460811
1075771511
46783058
3904109078
1534123438
1495905678
Defect reports
The following behavior-changing defect reports were applied retroactively to previously published C++ standards.
| DR | Applied to | Behavior as published | Correct behavior |
|---|---|---|---|
| LWG 2180 | C++11 | seed_seq::generate is non-throwing
|
it may throw exceptions |