std::seed_seq:: generate
|
template
<
class
RandomIt
>
void generate ( RandomIt begin, RandomIt end ) ; |
(C++11부터) | |
편향될 수 있는 시드가 저장된
v
를 기반으로 32비트 부호 없는 정수 값으로 출력 범위
[
begin
,
end
)
를 채워 편향되지 않은 시드를 생성합니다.
- 만약 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 | 내장 비트 XOR 연산 |
| rshift | 내장 비트 오른쪽 시프트 연산 |
| T(x) | x xor (x rshift 27) |
생성 알고리즘은 다음 단계들로 구성되며, 여기서
S
i
는
begin
[
i
%
n
]
를,
V
i
는
v
[
i
]
를 나타냅니다:
[
0
,
m
)
범위 내에서 다음 작업들을 순서대로 수행합니다:
- z , 만약 k=0
- (k mod n)+V k-1 , 만약 0<k⩽z
- k mod n , 만약 z<k
로 설정합니다.
로 설정합니다.
로 설정합니다.
[
m
,
m
+
n
)
범위 내에서, 다음 연산들을 순서대로 수행합니다:
로 설정합니다.
로 설정합니다.
로 설정합니다.
매개변수
| begin, end | - | 출력 범위를 나타내는 반복자 |
예외
RandomIt
연산이
begin
과
end
에서 발생시키는 예외만을 던집니다.
참고 사항
생성 알고리즘은 Makoto Matsumoto와 Takuji Nishimura 의 메르센 트위스터 생성기 초기화 시퀀스를 기반으로 하여, Mutsuo Saito가 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이라고 가정합니다. // // Step 1: 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); // // 첫 번째 반복, 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; } // // Step 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++ 표준에 소급 적용되었습니다.
| DR | 적용 대상 | 게시된 동작 | 올바른 동작 |
|---|---|---|---|
| LWG 2180 | C++11 |
seed_seq::generate
는 예외를 발생시키지 않음
|
예외를 발생시킬 수 있음 |