質問

範囲[0.0、1.0)で均一な分布を取得したい

可能であれば、実装に / dev / urandomからのランダムバイトを使用させてください。

ソリューションがスレッドセーフである場合も良いでしょう。不明な場合は、その旨をお知らせください。

いくつかの解決策を参照してください。他の回答を読んだ後で考えました。

役に立ちましたか?

解決 2

これはかなり良い方法のようです:

unsigned short int r1, r2, r3;
// let r1, r2 and r3 hold random values
double result = ldexp(r1, -48) + ldexp(r2, -32) + ldexp(r3, -16);

これは、NetBSDのdrand48実装に基づいています。

他のヒント

シンプル:IEEEを想定した場合、doubleの精度は52ビットです。したがって、(たとえばdev / urandomからバイトを読み取ることにより)52ビット(またはそれ以上)の符号なしランダム整数を生成し、それをdoubleに変換し、2 ^(ビット数)で除算します。

これにより、52番目の2進数までの数値的に均一な分布(値が特定の範囲内にある確率が範囲に比例する)が得られます。

複雑:ただし、範囲[0,1)には、上記では生成できないdouble値が多数あります。具体的には、範囲[0,0.5)の半分の値(最下位ビットが設定されている値)は発生しません。範囲[0,0.25)の4分の3の値(最低2ビットのいずれかが設定されているもの)は発生しないなど、2 ^ -51未満の正の値が1つだけになるまで、そのような価値の数十億を表すことができる二重であるにもかかわらず。そのため、指定された範囲全体で完全に正確であるとは言えません。

もちろん、結果の数が平均して小さすぎるため、等しい確率でこれらのダブルの1つを選択する必要はありません。結果が特定の範囲内にある確率は、範囲に比例する必要がありますが、どの範囲で機能するかについてより高い精度が必要です。

私は次の作品を考える。私はこのアルゴリズムを特に研究もテストもしていません(おそらくコードがないという方法でわかるかもしれません)。そして、個人的には、それが有効であることを示す適切な参照を見つけなければ使用しません。しかし、ここに行きます:

  • 52で指数を開始し、52ビットのランダムな符号なし整数を選択します(52ビットの仮数を想定)。
  • 整数の最上位ビットが0の場合、指数を1増やし、整数を左にシフトし、最下位ビットを新しいランダムビットで埋めます。
  • 最も重要な場所で1を押すか、倍数(1023。または1022)に対して指数が大きくなりすぎるまで繰り返します。
  • 1が見つかった場合、値を2 ^ exponentで除算します。すべてゼロになった場合、0を返します(実際には特別なケースではありませんが、0が返される可能性が非常に低いことを強調します[編集:実際に特別なケースになる可能性-生成するかどうかによって異なりますそうでない場合は、行に十分な0があれば、残っているものをすべて破棄して0を返します。しかし、実際には、これは無視できるほどまれではありません(ランダムソースがランダムでない場合を除く)。

このようなランダムなdoubleの実際の使用が実際にあるかどうかはわかりません。ランダムの定義は、それが何のためにあるかによって異なります。ただし、その重要なビットの52個すべてがランダムであるというメリットがある場合、これは実際に役立つ可能性があります。

ファイルからの読み取りはスレッドセーフなので、fopen()を使用して/ dev / urandomから読み取ると、「真のランダム」が得られます。バイト。

潜在的な落とし穴があるかもしれませんが、そのようなバイトのセットを整数としてアクセスし、そのサイズの最大整数で割ると、ほぼその分布で0から1の浮動小数点値が得られます。

例:

FILE* f = fopen("/dev/urandom", "r");
int32_t int;
fread(&int, sizeof(int32_t), 1, f);
fclose(f);
double theRandomValue = int / (double) (2 ** 32 - 1);

秘trickは、要件を満たす54ビットのランダマイザーが必要なことです。これらの54ビットを仮数部に固定するための結合を備えた数行のコードと、あなたの番号があります。トリックはダブルフロートではなく、希望するランダマイザーです。

#include <stdlib.h>
printf("%f\n", drand48());

/ dev / random:

double c;
fd = open("/dev/random", O_RDONLY);
unsigned int a, b;
read(fd, &a, sizeof(a));
read(fd, &b, sizeof(b));
if (a > b)
   c = fabs((double)b / (double)a);
else
    c = fabs((double)a / (double)b);

cはランダムな値です

/ dev / urandomはPOSIXではなく、一般に入手できません。

[0,1)で一様にdoubleを生成する標準的な方法は、範囲[0,2 ^ N)の整数を生成し、2 ^ Nで除算することです。あなたの好きな乱数ジェネレーターを選んで使用してください。シミュレーションの場合、私のものは Mersenne Twister です。これは非常に高速ですが、まだ十分に相関していないためです。 。実際には、これはあなたのためにそれを行うことができ、小さい数字に対してより高い精度を与えるバージョンさえ持っています。通常、最初にシードを指定します。これにより、デバッグや他のユーザーに結果を表示するための再現性が向上します。もちろん、コードがシードとして/ dev / urandomからランダムな番号を取得するよう指定することもできます。

暗号化の目的では、代わりに openssl などの標準的な暗号化ライブラリのいずれかを使用する必要があります)実際、使用可能な場合は/ dev / urandomを使用します。

スレッドの安全性については、少なくとも標準インターフェイスではほとんどの場合そうではないため、レイヤーを最上部に構築するか、1つのスレッドでのみ使用する必要があります。スレッドセーフなものは、変更する状態を提供するので、代わりに複数の非対話型乱数ジェネレーターを効果的に実行しますが、これは探しているものではない場合があります。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top