std::uniform_real_distribution
.
今年の Going Native カンファレンスで、STL による非常に優れた講演があり、可能な限り標準ディストリビューションを使用する必要がある理由が説明されています。手短に言えば、手作業で作成されたコードは、笑えるほど品質が悪い ( と考えstd::rand() % 100
てください) か、より微妙な均一性の欠陥がある傾向が(std::rand() * 1.0 / RAND_MAX) * 99
あります。
編集: libstdc++ の の実装を調べたところ、次のstd::uniform_real_distribution
ことがわかりました。
この実装では、範囲内で[dist_min, dist_max)
生成された数値から単純な線形変換を使用して、範囲内の数値を生成します[0, 1)
。を使用してこのソース番号を生成しますstd::generate_canonical
。その実装は、ここ(ファイルの最後) にあります。整数として表され、ここでは* で示される分布の範囲がターゲット型の仮数部に収まるstd::generate_canonical
回数 ( で示されるk
)を決定します。次に行うことは、基本的に、仮数の のサイズのセグメントごとに 1 つの数値を生成し、算術演算を使用して、それに応じて各セグメントに入力することです。結果の値の式は、次のように表すことができます。r
[0, r)
r
Σ(i=0, k-1, X/(r^i))
ここでX
は の確率変数です[0, r)
。範囲による各除算は、それを表すために使用されるビット数 (つまりlog2(r)
) によるシフトに相当するため、対応する仮数セグメントが埋められます。このようにして、ターゲット型の精度全体が使用され、結果の範囲が であるため[0, 1)
、指数は0
** (モジュロ バイアス) のままであり、指数。
このメソッドが暗号学的に安全であるという暗黙の了解は信頼できません (そして、 のサイズの計算でオフバイワン エラーが発生する可能性があるのではないかと疑っていますr
) が、Boost 実装よりも均一性の点ではるかに信頼できると思います投稿されており、をいじるよりも間違いなくstd::rand
優れています。
ブースト コードは、実際にはこのアルゴリズムの縮退ケースであることに注意してください。つまり、入力範囲がそのサイズを表すのに少なくとも 23 ビット (IEE 754 単精度) または少なくとも 52 ビットを必要とする場合k = 1
、同等であることを意味します。 (倍精度)。これは、最小範囲がそれぞれ ~840 万または ~4.5e15 であることを意味します。この情報に照らして考えると、バイナリ ジェネレーターを使用している場合、Boost の実装で問題が解決するとは思えません。
libc++ の実装を簡単に見てみると、同じアルゴリズムを使用しているように見えますが、実装が少し異なります。
(*)r
は、実際には入力プラス 1の範囲です。これによりmax
、urng の値を有効な入力として使用できます。
(**) 厳密に言えば、エンコードされた指数は ではありません0
。IEEE 754 は仮数の基数の前に暗黙の先行 1 をエンコードするためです。ただし、概念的には、これはこのアルゴリズムには関係ありません。