6

rand()標準とメソッドを使用しない方法で、0から1までのC++で均一な乱数を生成したいと思いますsrand(time(NULL))。これは、時計の同じ秒内にアプリケーションを複数回実行すると、シードがまったく同じになり、同じ出力が生成されるためです。

ブーストやOS/コンパイラの詳細に依存したくありません。x86を想定できます。

これを行う別の方法は、TR1(私はC ++ 11を持っていません)を使用し/dev/random、何らかの方法でシードすることであるように思われますか?

今私はこれを持っていますが、それでもtime(NULL)1秒以内にうまく機能しないシードとして使用します:

#include <iostream> 
#include <tr1/random> 

int main() 
{ 
  std::tr1::mt19937 eng; 
  eng.seed(time(NULL)); 
  std::tr1::uniform_int<int> unif(1, RAND_MAX); 
  int u = unif(eng); 
  std::cout << (float)u/RAND_MAX << std::endl; 
} 
4

3 に答える 3

7

OPの要請による投稿:

これはまだコンパイラ固有ですが、ほぼすべてのx86ターゲットコンパイラで機能します。

#ifdef _WIN32

//  Windows
#define rdtsc  __rdtsc

#else

//  For everything else
unsigned long long rdtsc(){
    unsigned int lo,hi;
    __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
    return ((unsigned long long)hi << 32) | lo;
}

#endif

int main() 
{ 
  std::tr1::mt19937 eng; 
  eng.seed( rdtsc() );    //  Seed with rdtsc.
  std::tr1::uniform_int<int> unif(1, RAND_MAX); 
  int u = unif(eng); 
  std::cout << (float)u/RAND_MAX << std::endl; 
} 

ここでの考え方は、乱数ジェネレーターにrdtscサイクルカウンターをシードすることです。

これが機能する理由は、rdtscサイクルカウンターがCPU周波数とほぼ(多くの場合同じ)速度で反復するためです。したがって、2回の呼び出しで同じ値が返される可能性は非常に低く、RNGの優れたシードになります。

于 2011-12-28T21:13:14.613 に答える
4

[tr.rand.device]のTR1はrandom_device、実装に依存するソースから符号なしintを生成するクラスを指定します。したがって、私は自分でコンパイルしていませんが、以下は機能するはずです。

int main() {
  std::tr1::random_device dev_random;
  std::tr1::mt19937 eng(dev_random());
  ...

TR1では、dev_randomを呼び出さずに直接渡すと、engの状態がよりランダムに機能して初期化されますが、C ++ 11では、シード引数を別のクラスにラップする必要があります。引数の呼び出しは両方のライブラリで機能するので、より厳しいニーズがない限り、保守性のためにそうします。

于 2011-12-28T21:30:15.997 に答える
1

問題は、乱数ジェネレーターをシードする方法に関連しています。明らかに、time(NULL)を使用してシードすると、シードされたときにその1秒以内に同じPRNGシーケンスが生成されます。これはランドをシードする最も一般的な方法ですが、この問題のために残念ながら悪い習慣です。それだけでなく、結果に偏りが生じる可能性があることを読みました。

同じ値でシードされた場合、すべてのPRNGが同じ結果を生成することに注意してください。したがって、問題はジェネレーターに関係するのではなく、シードに関係します。

ほんの数週間前にここでシードについて質問したところ、次の記事へのリンクが提供されました。 バイオインフォマティクスアプリケーションの(疑似)乱数生成のグッドプラクティス ジェネレータのシードまたはウォーミングアップに関するセクションを参照してください。

rand()は最良の乱数ジェネレーターではありませんが、適切にシードされている場合は多くの場合に適しています。繰り返しシーケンスが非常に大きい場合に、より良いものが必要な場合は、そのリンクにいくつか提供されています。または、TR1ベースのものを使用してください。個人的には、より移植性の高いC ++ 03ベースのコードを使用し、TR1を避けます。

また、代替PRNGアルゴリズムとしてキャリー付き倍算を検討してください。

于 2011-12-28T21:10:09.157 に答える