Skip to content

Commit f1b341a

Browse files
committed
generate_canonical : C++26で範囲外の値が生成されなくなった仕様変更に対応 #1239
仕様として変更を記載したので、Qiitaの考察・検証の記事への参照を削除
1 parent 5486a04 commit f1b341a

3 files changed

Lines changed: 47 additions & 8 deletions

File tree

reference/random/generate_canonical.md

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@
77
```cpp
88
namespace 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`に変更し、棄却法による新しいアルゴリズムを導入

reference/random/uniform_real_distribution.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,13 @@ namespace std {
2020
- `RealType` : 生成する実数の型。
2121
2222
23+
## 備考
24+
- `uniform_real_distribution`の実装は、内部的に[`std::generate_canonical()`](generate_canonical.md)を使用している環境がある
25+
- C++23まではその`std::generate_canonical()`の仕様上、浮動小数点数の丸めにより指定範囲外の値(上限値`b`)が生成されることがあった
26+
- C++26では`std::generate_canonical()`に棄却法が導入されたことで、この問題は解消された
27+
- [P0952R2 A New Specification for `generate_canonical`](https://open-std.org/jtc1/sc22/wg21/docs/papers/2023/p0952r2.html)
28+
29+
2330
## メンバ関数
2431
### 構築・リセット
2532

reference/random/uniform_real_distribution/op_constructor.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,5 +85,3 @@ int main()
8585
## 参照
8686

8787
- [P0935R0 Eradicating unnecessarily explicit default constructors from the standard library](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0935r0.html)
88-
- [C++ の std::uniform_real_distribution はあまり信用できない。](https://qiita.com/Nabetani/items/b6b5f80c77b92ff8bd9f)
89-
- a ≤ x < b なるx を返すはずであるが、その範囲外の値が返ってくるライブラリ実装が存在することの指摘。

0 commit comments

Comments
 (0)