77``` cpp
88namespace std {
99 template<class RealType, std::size_t bits, class URBG>
10- RealType generate_canonical(URBG& g);
10+ RealType generate_canonical(URBG& g); // (1) C++11
11+
12+ template<class RealType, std::size_t digits, class URBG>
13+ RealType generate_canonical(URBG& g); // (1) C++26
1114}
1215```
1316
@@ -18,17 +21,50 @@ namespace std {
1821
1922## テンプレートパラメータ
2023- `class RealType` : 生成する実数の型。
21- - `size_t bits` : 生成する実数における仮数部への分解能の最低要求。最大値は `std::`[`numeric_limits`](/reference/limits/numeric_limits.md)`<RealType>::`[`digits`](/reference/limits/numeric_limits/digits.md) 。
24+ - `size_t bits` : 生成する実数における仮数部への分解能の最低要求。最大値は `std::`[`numeric_limits`](/reference/limits/numeric_limits.md)`<RealType>::`[`digits`](/reference/limits/numeric_limits/digits.md)
25+ - C++26で`digits`に名称変更
26+ - `size_t digits` : 生成する実数における基数非依存の桁数としての分解能の最低要求。最大値は `std::`[`numeric_limits`](/reference/limits/numeric_limits.md)`<RealType>::`[`digits`](/reference/limits/numeric_limits/digits.md) 。
2227- `class URBG` : 一様乱数生成器の型。
2328
2429## 関数パラメータ
2530- URBG& g : 一様乱数生成器。
2631
2732
33+ ## 効果
34+ - C++11からC++23まで :
35+ 以下の変数を定義する。
36+ - `R` = `g.`[`max()`](/reference/random/uniform_random_bit_generator.md) `-` `g.`[`min()`](/reference/random/uniform_random_bit_generator.md) `+ 1`
37+ - `k` = max(1, ⌈`bits` / log<sub>2</sub>`R`⌉)
38+ - `S` = `g()` から `k` 回呼び出した結果を `R` のべき乗で重み付けして累積した値
39+
40+ 戻り値は `S` / `R`<sup>`k`</sup> となる。ただし浮動小数点数の丸めにより、結果が1.0になる場合がある。
41+
42+ - C++26 :
43+ 以下の変数を定義する。
44+ - `r` = [`numeric_limits`](/reference/limits/numeric_limits.md)`<RealType>::`[`radix`](/reference/limits/numeric_limits/radix.md)
45+ - `R` = `g.`[`max()`](/reference/random/uniform_random_bit_generator.md) `-` `g.`[`min()`](/reference/random/uniform_random_bit_generator.md) `+ 1`
46+ - `d` = min(`digits`, [`numeric_limits`](/reference/limits/numeric_limits.md)`<RealType>::`[`digits`](/reference/limits/numeric_limits/digits.md))
47+ - `k` = `R`<sup>`k`</sup> ≥ `r`<sup>`d`</sup> を満たす最小の整数
48+ - `x` = ⌊`R`<sup>`k`</sup> / `r`<sup>`d`</sup>⌋
49+
50+ 以下の手順で乱数を生成する。
51+
52+ 1. `g()` を `k` 回呼び出して値 `S` を生成する
53+ 2. `S` ≥ `x` · `r`<sup>`d`</sup> の場合、手順1に戻って再試行する(棄却法)
54+ 3. 戻り値は ⌊`S` / `x`⌋ / `r`<sup>`d`</sup> となる
55+
56+ この棄却法により、浮動小数点数の丸めで結果が1.0になる問題が解消され、戻り値は必ず0以上1未満となることが保証される。
57+
58+
2859## 例外
2960`URBG g` が例外を送出する場合はそれに準ずる。
3061
3162
63+ ## 備考
64+ - C++23まではアルゴリズムの仕様上、浮動小数点数の丸めにより値`1.0`が生成されることがあった
65+ - C++26では棄却法(reject-and-retry)方式が導入され、戻り値が\[0.0, 1.0\)の範囲内であることが保証されるようになった
66+
67+
3268## 例
3369```cpp example
3470#include <random>
@@ -80,10 +116,8 @@ int main()
80116- GCC 4.9時点において、` float ` 型を指定した場合に、値` 1.0 ` が生成されることがあるバグがある([ Bug 63176] ( https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63176 ) )
81117- Clang 3.3時点において、値` 1.0 ` が生成されることがある([ Bug 18767] ( https://llvm.org/bugs/show_bug.cgi?id=18767 ) )
82118
83- ### 参考
84- - N3337 p.909 §26.5.7.2
85-
86-
87119## 参照
88120- [ P0346R1 A ` <random> ` Nomenclature Tweak] ( http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0346r1.pdf )
89121 - URNGをURBGに変更
122+ - [ P0952R2 A New Specification for ` generate_canonical ` ] ( https://open-std.org/jtc1/sc22/wg21/docs/papers/2023/p0952r2.html )
123+ - C++26でテンプレートパラメータ名を` bits ` から` digits ` に変更し、棄却法による新しいアルゴリズムを導入
0 commit comments