From 2cd7a7b47c1023a4e95ed915ae18429034113633 Mon Sep 17 00:00:00 2001 From: Akira Takahashi Date: Thu, 19 Dec 2024 19:08:32 +0900 Subject: [PATCH] fix --- reference/random/philox_engine.md | 130 ++++++++++++++++-------------- 1 file changed, 68 insertions(+), 62 deletions(-) diff --git a/reference/random/philox_engine.md b/reference/random/philox_engine.md index 433da2b2ba..5229682db6 100644 --- a/reference/random/philox_engine.md +++ b/reference/random/philox_engine.md @@ -18,27 +18,28 @@ namespace std { * philox4x64[link philox4x64.md] ## 概要 -`philox_engine`クラスは、カウンターベースのPhilox法による擬似乱数生成エンジンである。 +`philox_engine`クラスは、カウンターベースのPhilox法による擬似乱数生成エンジンである。 Philox法は、以下のような特徴を持つ: -1. 小さい容量の状態をもつ (Philox4x32の状態は10 * 32ビット個の要素) +1. 小さい容量の状態をもつ (Philox4x32の状態は32ビットの値 * 10個の要素) 2. 長い周期をもつ (Philox4x32の周期は2130) 3. ベクトル化・並列化がしやすい -`philox_engine`は、m = 2w−1であるとして、区間`[0, m]`の符号なし整数の乱数を生成する。 +`philox_engine`は、 $ m = 2^{w}−1 $ であるとして、区間`[0, m]`の符号なし整数の乱数を生成する。 - オブジェクトの状態としては、以下をもつ: - - n個のwビットの符号なし整数からなるシーケンスX - - n/2個の`result_type`値からなるシーケンスK - - n個の`result_type`値からなるシーケンスY + - n個のwビットの符号なし整数からなるシーケンス $X$ + - n/2個の`result_type`値からなるシーケンス $K$ + - n個の`result_type`値からなるシーケンス $Y$ - スカラー値i ここでそれぞれの値は以下の意味をもつ: - - Xは $$ n \cdot w $$ ビットの符号なし整数のカウンター値 $$ Z=\sum_{j=0}^{n-1}X_{j} \cdot 2^{wj} $$ の解釈である - - Kはキー - - Yは生成された値のバッファ - - iはYバッファのインデックス値 + - $X$ は $ n \cdot w $ ビットの符号なし整数のカウンター値 $ Z=\sum_{j=0}^{n-1}X_{j} \cdot 2^{wj} $ の解釈である + - $K$ はキー + - $Y$ は生成された値のバッファ + - $i$ は $Y$ バッファのインデックス値 + - 乱数生成アルゴリズムは、遷移アルゴリズムを適用したあと、Yのi番目に格納された値を返す - 状態遷移は、以下のアルゴリズムで実行される: ``` @@ -54,6 +55,7 @@ Philox法は、以下のような特徴を持つ: - 1. 前のラウンドの出力シーケンスX'(第1ラウンドの場合はX)を並べ替えて中間状態Vを得る: $$ V_{j} = X'_{f(j)} $$ ここでj = 0, …, n-1であり、`f(j)`は以下のテーブルで定義される (n=2のシーケンスは順列ではない): + | | j=0 | j=1 | j=2 | j=3 | j=4 | j=5 | j=6 | j=7 | j=8 | j=9 | j=10 | j=11 | j=12 | j=13 | j=14 | j=15 | |------|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|------|------|------|------|------|------| | n=2 | 0 | 1 | | | | | | | | | | | | | | | @@ -61,19 +63,31 @@ Philox法は、以下のような特徴を持つ: | n=8 | 2 | 1 | 4 | 7 | 6 | 5 | 0 | 3 | | | | | | | | | | n=16 | 0 | 9 | 2 | 13 | 16 | 11 | 4 | 15 | 10 | 7 | 12 | 13 | 14 | 5 | 8 | 1 | - - 2. シーケンスVの要素には以下の計算が適用される: - $$ X'_{2 \cdot k} = mullo(V_{2 \cdot k + 1'} M_{k'} w) $$ - $$ X'_{2 \cdot k + 1} = mulhi(V_{2 \cdot k + 1'} M_{k'} w) xor key_k^q xor V_{2 \cdot k} $$ + - 2. シーケンス $V$ の要素には以下の計算が適用される: + $$ X'_{2 \cdot k} = mullo(V_{2 \cdot k + 1},\ M_{k},\ w) $$ + $$ X'_{2 \cdot k + 1} = mulhi(V_{2 \cdot k + 1},\ M_{k}, w)\ xor\ key_k^q\ xor\ V_{2 \cdot k} $$ + + - ここで以下のように定義する: + - `mullo(a, b, w)`関数は、`a`と`b`を掛けた剰余の下半分を返す: $ a \cdot b\ mod \ 2^{w} $ + - `mulhi(a, b, w)`関数は、`a`と`b`を掛けた上半分を返す: $ \left( \lfloor (a \cdot b) / 2^{w} \rfloor \right) $ 。`k`は0, …, n/2-1のインデックスシーケンスである + - `q`は0, …, r - 1のラウンドのインデックスである + - $ key_k^q $ はラウンド`q`の`k`番目のラウンドキーであり、 $ key_k^q = \left( K_{k}\ +\ q \cdot C_{k} \right)\ mod\ 2^{w} $ + - $ K_{k} $ はシードで一度生成されたキーであり、[`seed()`](philox_engine/seed.md)関数が呼ばれない限り固定である + - $ M_{k} $ は`multipliers`である + - $ C_{k} $ は`round_consts`である - - ここで +- 一回のラウンド関数が`r`回適用されたあと、Philoxはシーケンス`Y=X'`を返す +- このクラスオブジェクトのテキスト表現は、 $ K_{0}, …, K_{n/2-1}, X_{0}, …, X_{n-1}, i $ の順で対応する + - 備考: ストリーム演算子は、必要に応じて $K$ と $X$ から $Y$ を再構築できる ### テンプレートパラメータ -* `UIntType` : 生成する符号なし整数の型。 -* `w` : ワードサイズ。状態シーケンス内での各ワードのビット数 -* `n` : ワード数 -* `r` : ラウンド数。大きいほど乱数の質が高くなり、分布が改善する -* `consts` : 内部で使用する定数値 +- `UIntType` : 生成する符号なし整数の型。 +- `w` : ワードサイズ。状態シーケンス内での各ワードのビット数 +- `n` : ワード数 +- `r` : ラウンド数 +- `consts` : 内部で使用する`n`個の定数値 + - $ M_{k} $ と $ C_{k} $ の値を表し、以下のようにグループ化される: $ \left[ M_{0}, C_{0}, M_{1}, C_{1}, M_{2}, C_{2}, …, M_{n/2-1}, C_{n/2-1} \right] $ ### 適格要件 @@ -83,75 +97,68 @@ Philox法は、以下のような特徴を持つ: ### 周期 -n * 2w * n +$ n \cdot 2^{w \cdot n} $ ### サイズ -r * wビット +$ r \cdot w $ ビット ## メンバ関数 ### 構築・シード | 名前 | 説明 | 対応バージョン | -|-------------------------------------------------------------------------|------------------|-------| -| [`(constructor)`](mersenne_twister_engine/op_constructor.md) | コンストラクタ | C++11 | -| `~mersenne_twister_engine() = default;` | デストラクタ | C++11 | -| [`seed`](mersenne_twister_engine/seed.md) | シードを設定する | C++11 | +|-----------------------------------------------------|------------------|-------| +| [`(constructor)`](philox_engine/op_constructor.md) | コンストラクタ | C++26 | +| `~philox_engine() = default;` | デストラクタ | C++26 | +| [`seed`](philox_engine/seed.md) | シードを設定する | C++26 | +| [`set_counter`](philox_engine/set_counter.md) | カウンターを設定する | C++26 | ### 生成 | 名前 | 説明 | 対応バージョン | -|------------------------------------------------------|--------------------|-------| -| [`operator()`](mersenne_twister_engine/op_call.md) | 擬似乱数を生成する | C++11 | -| [`discard`](mersenne_twister_engine/discard.md) | 指定した回数だけ擬似乱数を生成し、内部状態を進める | C++11 | +|------------------------------------------|--------------------|-------| +| [`operator()`](philox_engine/op_call.md) | 擬似乱数を生成する | C++26 | +| [`discard`](philox_engine/discard.md) | 指定した回数だけ擬似乱数を生成し、内部状態を進める | C++26 | ## 静的メンバ関数 ### エンジンの特性 | 名前 | 説明 | 対応バージョン | -|-------------------------------------------|--------------------------------|-------| -| [`min`](mersenne_twister_engine/min.md) | 生成し得る値の最小値を取得する | C++11 | -| [`max`](mersenne_twister_engine/max.md) | 生成し得る値の最大値を取得する | C++11 | +|-------------------------------|--------------------------------|-------| +| [`min`](philox_engine/min.md) | 生成し得る値の最小値を取得する | C++26 | +| [`max`](philox_engine/max.md) | 生成し得る値の最大値を取得する | C++26 | ## メンバ型 | 型 | 説明 | 対応バージョン | |---------------|-------------------|-------| -| `result_type` | 擬似乱数生成結果の符号なし整数型 `UIntType`。 | C++11 | +| `result_type` | 擬似乱数生成結果の符号なし整数型 `UIntType`。 | C++26 | ## メンバ定数 | 定数 | 説明 | 対応バージョン | |---------------|-------------------|-------| -| `static constexpr size_t word_size` | ワードサイズ。状態シーケンス内での各ワードのビット数。テンプレートパラメータ`w`。 | C++11 | -| `static constexpr size_t state_size` | 状態のサイズ。状態シーケンスの要素数。生成される値が再発する程度を調整するための値。テンプレートパラメータ`n`。 | C++11 | -| `static constexpr size_t shift_size` | シフトサイズ。各ひねり(twist)時にシーケンスから選択する他の値が、`m`要素離れるようにする。テンプレートパラメータ`m`。 | C++11 | -| `static constexpr size_t mask_bits` | マスクのビットサイズ。各ひねりに対する分離ポイントのマスクサイズ。テンプレートパラメータ`r`。 | C++11 | -| `static constexpr UIntType xor_mask` | XORのマスク。各ひねりに対して、線形関数としてXORする値。テンプレートパラメータ`a`。 | C++11 | -| `static constexpr size_t tempering_u` | 調律シフトのパラメータ。生成アルゴリズムによって使用される、ごちゃ混ぜ処理のシフト値。テンプレートパラメータ`u`。 | C++11 | -| `static constexpr UIntType tempering_d` | 調律ビットマスクのパラメータ。生成アルゴリズムによって使用される、ごちゃ混ぜ処理のビットマスク値。テンプレートパラメータ`d`。 | C++11 | -| `static constexpr size_t tempering_s` | 調律シフトのパラメータ。生成アルゴリズムによって使用される、ごちゃ混ぜ処理のシフト値。テンプレートパラメータ`s`。 | C++11 | -| `static constexpr UIntType tempering_b` | 調律ビットマスクのパラメータ。生成アルゴリズムによって使用される、ごちゃ混ぜ処理のビットマスク値。テンプレートパラメータ`b`。 | C++11 | -| `static constexpr size_t tempering_t` | 調律シフトのパラメータ。生成アルゴリズムによって使用される、ごちゃ混ぜ処理のシフト値。テンプレートパラメータ`t`。 | C++11 | -| `static constexpr UIntType tempering_c` | 調律ビットマスクのパラメータ。生成アルゴリズムによって使用される、ごちゃ混ぜ処理のビットマスク値。テンプレートパラメータ`c`。 | C++11 | -| `static constexpr size_t tempering_l` | 調律シフトのパラメータ。生成アルゴリズムによって使用される、ごちゃ混ぜ処理のシフト値。テンプレートパラメータ`l`。 | C++11 | -| `static constexpr UIntType initialization_multiplier` | 初期化の乗数。ひとつの値をシードとする際の、状態シーケンスのシードとして使用する初期化乗数。テンプレートパラメータ`f`。 | C++11 | -| `static constexpr result_type default_seed` | デフォルトのシード値。`5489u` | C++11 | +| `static constexpr size_t word_size` | ワードサイズ。状態シーケンス内での各ワードのビット数。テンプレートパラメータ`w`。 | C++26 | +| `static constexpr size_t word_count` | 状態のサイズ。状態シーケンスの要素数。生成される値が再発する程度を調整するための値。テンプレートパラメータ`n`。 | C++26 | +| `static constexpr size_t round_count` | ラウンド数。大きいほど乱数の質が高くなり、分布が改善する。テンプレートパラメータ`r`。 | C++26 | +| `static constexpr array multipliers` | カウンター値に対する乗数。 | C++26 | +| `static constexpr array` | ラウンドごとのキー値 | C++26 | +| `static constexpr result_type default_seed` | デフォルトのシード値。`20111115u` | C++26 | ## 非メンバ関数 | 名前 | 説明 | 対応バージョン | -|-----------------------------------------------------------|----------------------|-------| -| [`operator==`](mersenne_twister_engine/op_equal.md) | 等値比較 | C++11 | -| [`operator!=`](mersenne_twister_engine/op_not_equal.md) | 非等値比較 | C++11 | -| [`operator<<`](mersenne_twister_engine/op_ostream.md) | ストリームへの出力 | C++11 | -| [`operator>>`](mersenne_twister_engine/op_istream.md) | ストリームからの入力 | C++11 | +|-----------------------------------------------|----------------------|-------| +| [`operator==`](philox_engine/op_equal.md) | 等値比較 | C++26 | +| `operator!=` | 非等値比較 (`==`により使用可能) | C++26 | +| [`operator<<`](philox_engine/op_ostream.md) | ストリームへの出力 | C++26 | +| [`operator>>`](philox_engine/op_istream.md) | ストリームからの入力 | C++26 | ## 例 @@ -163,20 +170,19 @@ int main() { std::random_device seed_gen; - // mersenne_twister_engineのパラメータ設定済み別名であるmt19937を使用する。 + // philox_engineのパラメータ設定済み別名であるphilox4x32を使用する。 // ランダムなシードを使用して初期化 - std::mt19937 engine(seed_gen()); + std::philox4x32 engine{seed_gen()}; for (int i = 0; i < 10; ++i) { // 乱数を生成 std::uint32_t result = engine(); - std::cout << result << std::endl; } } ``` * std::uint32_t[link /reference/cstdint/uint32_t.md] -* engine()[link mersenne_twister_engine/op_call.md] +* engine()[link philox_engine/op_call.md] ### 出力例 ``` @@ -194,16 +200,16 @@ int main() ## バージョン ### 言語 -- C++11 +- C++26 ### 処理系 -- [Clang](/implementation.md#clang): ?? -- [GCC](/implementation.md#gcc): 4.7.2 [mark verified] +- [Clang](/implementation.md#clang): 19 [mark noimpl] +- [GCC](/implementation.md#gcc): 14 [mark noimpl] - [ICC](/implementation.md#icc): ?? - [Visual C++](/implementation.md#visual_cpp): ?? ## 参照 -* [Mersenne Twister Home Page](http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/mt.html) -* [メルセンヌ・ツイスタ - Wikipedia](https://ja.wikipedia.org/wiki/メルセンヌ・ツイスタ) -* GCC(libstdc++) 4.8以降では、``ヘッダに、SSE最適化されたメルセンヌ・ツイスターである`simd_fast_mersenne_twister_engine`クラスが実装されている - +- [P1932R0 Extension of the C++ random number generators](http://open-std.org/JTC1/SC22/WG21/docs/papers/2019/p1932r0.pdf) + - C++にPhilox乱数生成器が最初に提案された文書 +- [Parallel Random Numbers: As Easy as 1, 2, 3](https://www.thesalmons.org/john/random123/papers/random123sc11.pdf) + - 2011年に発表されたこの論文でPhilox乱数生成器が考案された