[0.0, 1.0) の範囲で一様分布を取得したい
可能であれば、実装で/dev/urandom からのランダム バイトを使用できるようにしてください。
あなたのソリューションがthread-safeであればそれもいいでしょう。不明な場合は、その旨をご指示ください。
他の回答を読んだ後に考えた解決策を見てください。
[0.0, 1.0) の範囲で一様分布を取得したい
可能であれば、実装で/dev/urandom からのランダム バイトを使用できるようにしてください。
あなたのソリューションがthread-safeであればそれもいいでしょう。不明な場合は、その旨をご指示ください。
他の回答を読んだ後に考えた解決策を見てください。
これはかなり良い方法のようです:
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ビットです。したがって、52ビット(またはそれ以上)の符号なし乱数を生成し(たとえば、dev / urandomからバイトを読み取ることにより)、それをdoubleに変換し、2 ^(ビット数)で除算します。
これにより、52番目の2進数まで、数値的に均一な分布(値が特定の範囲内にある確率が範囲に比例する)が得られます。
複雑:ただし、[0,1)の範囲には、上記では生成できないdouble値が多数あります。具体的には、[0,0.5)の範囲の半分の値(最下位ビットが設定されている値)は発生しません。[0,0.25)の範囲の値の4分の3(少なくとも2ビットのいずれかが設定されている値)などは発生しません。2^-51未満の正の値が1つだけ可能です。ダブルはそのような値の数十億を表すことができますが。したがって、指定された範囲全体で完全な精度まで真に均一であるとは言えません。
もちろん、同じ確率でこれらのdoubleの1つを選択することは望ましくありません。その場合、結果の数は平均して小さすぎるためです。結果が特定の範囲内にある確率は、その範囲に比例する必要がありますが、どの範囲で機能するかについてはより高い精度が必要です。
以下の作品だと思います。私はこのアルゴリズムを特に研究またはテストしていません(おそらくコードがないことからわかるように)。個人的には、有効であることを示す適切な参照を見つけずに使用することはありません。しかし、ここに行きます:
このようなランダムダブルの実用性が実際にあるかどうかはわかりませんが、気に留めておいてください。ランダムの定義は、その目的にある程度依存する必要があります。しかし、その重要なビットの52個すべてがランダムであるという利点を得ることができる場合、これは実際に役立つ可能性があります。
ファイルからの読み取りはスレッドセーフなAFAIKであるため、 fopen() を使用して /dev/urandom から読み取ると、「真にランダムな」バイトが生成されます。
潜在的な落とし穴があるかもしれませんが、整数としてアクセスされるそのようなバイトのセットは、そのサイズの最大整数で割ると、ほぼその分布で 0 と 1 の間の浮動小数点値が得られると思います。
例えば:
#include <limits.h>
#include <stdint.h>
#include <stdio.h>
...
FILE* f = fopen("/dev/urandom", "r");
uint32_t i;
fread(&i, sizeof(i), 1, f); // check return value in real world code!!
fclose(f);
double theRandomValue = i / (double) (UINT32_MAX);
#include <stdlib.h>
printf("%f\n", drand48());
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 つのスレッドでのみ使用する必要があります。スレッドセーフのものは、変更する状態を提供するため、代わりに、相互作用しない複数の乱数ジェネレーターを効果的に実行しているため、探しているものではない可能性があります。
秘訣は、要件を満たす 54 ビットのランダマイザーが必要なことです。これらの 54 ビットを仮数に固定する共用体を含む数行のコードで、数値が得られます。トリックはダブルフロートではなく、希望するランダマイザーです。