2011-12-28 10 views
6

標準rand()srand(time(NULL))メソッドを使用しない方法で、0から1までのC++で一様乱数を生成したい。この理由は、私が同じ時計内で2回以上アプリケーションを実行すると、シードはまったく同じになり、同じ出力を生成することになります。TR1を使用してC++で乱数を生成する/ dev/random(弾力性<1秒未満)

私は、ブーストやOS /コンパイラの仕様に頼っていません。 x86が想定されます。

これを行う別の方法はTR1(私はC++ 11はありません)と何らかの方法で/dev/randomをシードすることです。

今、私はこれを持っているが、それはまだ1秒の実行中にうまく動作しませんシードとしてtime(NULL)を使用しています:

#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; 
} 
+0

OS /コンパイラ固有の機能を使用しますか? – Mysticial

+0

私はこれを避けたいです...私はこれをさまざまなシステムに展開します – gnychis

+0

どのように様々ですか?それらはまだすべてx86ですか? – Mysticial

答えて

7

投稿:

これはまだ多少コンパイラ固有のであるが、それでもほぼすべての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の優れたシードになります。

1

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

同じ値をシードした場合、EVERY PRNGは同じ結果を生成します。ですから、あなたの問題はジェネレータに関連していないので、より多くのものを播種することができます。

私はここに数週間前に播種に関する質問をし、役に立つかもしれない次の記事へのリンクを与えました。 Good Practice in (Pseudo) Random Number Generation for Bioinformatics Applications ジェネレータのシーディングまたはウォームアップのセクションを参照してください。

rand()は最良の乱数生成器ではありませんが、適切にシードされている場合は多くの場合適切です。リピートシーケンスが非常に大きい場合は、そのリンクにいくつかのものが用意されています。またはTR1ベースのものを使用します。個人的には、私はよりポータブルなC++ 03のコードを使い、TR1をクリアします。

代替PRNGアルゴリズムとしてMultiply with carryも考えてください。 OPの要求で

4

[tr.rand.device]のTR1は、実装依存のソースから符号なしintを生成するrandom_deviceクラスを指定します。だから、次は動作するはずです、私はそれを自分でコンパイルしていないにもかかわらず:よりランダムにENGの状態を動作し、初期化し、それを呼び出すことなく、直接dev_randomを渡し、

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

が、C++ 11であなたが種子をラップする必要があります他のクラスへの引数引数を呼び出すことは両方のライブラリで機能するので、あなたがより厳しいニーズを持っていない限り、メンテナンス性のためにそれを行います。

+0

'random_device()'コンストラクタから得られるランダムなデバイスについては保証がありません。 '/ dev/random'、'/dev/urandom'、 '' rdtsc''ベース、http://en.wikipedia.org/wiki/RdRand、あるいは別の疑似ライブラリであってもかまいません。実装は、選択肢の中から選択するコンストラクタへの文字列引数を定義することができますが、デフォルトはまともであるはずです。 –

+1

random_deviceは関数オブジェクトですので、 'eng(dev_random())' – Cubbi

+0

@Cubbi:いいえ、エンジンは整数を取るコンストラクタと関数オブジェクトを取るコンストラクタの両方を持っています: "' X(g) ' - エンジンは最初の内部状態が 'g'の連続呼び出しの結果によって与えられる。 - [tr.rand.req] table 16.これにより、最初の単語の代わりに状態全体を満たすことができます。 (もちろん、任意の実装が仕様全体を実装していない可能性もあります) –

関連する問題