2011-08-27 31 views
23

新しいC++ 11 Standardには乱数ジェネレータ専用の章があります。しかし、どのように私はこのようなコード化するために使用される最も簡単な、最も一般的なタスクを実行しますが、標準Cライブラリに頼らなくてはなら:C++ 11標準ライブラリを使用して乱数を生成するには

srand((unsigned int)time(0)); 
int i = rand();

は乱数エンジン、分布、および種子のための合理的なデフォルトがあります1つはすぐに使用できますか? default_random_engineの品質は実装依存である

std::default_random_engine e((unsigned int)time(0)); 
int i = e(); 

+0

ウィキペディア? http://en.wikipedia.org/wiki/C%2B%2B0x#Extensible_random_number_facility – quasiverse

+2

あなたのコードには何が問題なのですか? AFAIKでは、新しい乱数ジェネレータが、乱数生成の側面が本当に重要な、より深刻なアプリケーションに追加されました。 – GManNickG

+3

@GMan:公平になるために、新しい標準の乱数エンジンのいくつかは、シンプルかつ高速であると記述することができ、特に「深刻」とは見なさないでしょう。 –

答えて

30

あなたのような何かを行うことができるはず。 std::min_rand0またはstd::min_randを使用することもできます。

乱数エンジンをシードするには、timeではなく、実装から利用可能な乱数を使用するのが良いでしょう。

など。

​​
+1

明確にするために、「これは存在しませんが、存在していなければなりません」という意味で「これは必要ですか?」とあり、コンパイラはそれをサポートすべきですか? – GManNickG

+8

情報提供:この回答とOPの例の最大の違いは、コーダがエンジンの状態を制御することです。これは「e」にあります。 OPのコードでは、状態は 'rand'の中に静的なデータとして隠されています。これは、マルチスレッドのプログラムを扱う際の重要な違いです。 'rand'はスレッドを安全にするためにある種の保護を持たなければなりません。 'default_random_engine'はしません。複数のスレッドから呼び出す場合は、外部から同期メカニズムを提供します。これは、 'default_random_engine'を同期させる必要がなければ、より速くできることを意味します。 –

+0

@GMan:現時点で私がアクセスできる唯一の実装はサポートしていないので、コードをテストできませんでした。 –

2

既存のコードが新しい標準よりも前に適切だった場合は、引き続き使用されます。新たな乱数発生器は、より高い品質の擬似乱数を必要とするアプリケーションのために追加されました。確率的シミュレーション。

0

乱数生成は難しい問題です。本当にランダムな方法はありません。ゲーム環境をシードするランダム性を生成しているのであれば、あなたのアプローチはうまくいくはずです。 rand()にはいくつかの欠点があります。

暗号化キーを生成するためにランダム性が必要な場合は、S.O.Lです。その場合の最良の方法は、通常はメカニズムを持つオペレーティングシステムに出すことです。ランダム()であるPOSIX(または、もしあなたがそのように処分されていれば、/ dev/randomから読み込みます)。あなたは、ランダムなバイトを生成するためにRC4を使用することができ

https://www.securecoding.cert.org/confluence/display/seccode/MSC30-C.+Do+not+use+the+rand%28%29+function+for+generating+pseudorandom+numbers

0

:Windowsでは、CryptoAPIを使用することができます。これはおそらくあなたが望むプロパティを持っています。それは速く、かなり簡単に実装することができます。シードがわかっている場合、シーケンスはすべての実装で繰り返され、シードがわからない場合は完全に予測できません。 http://en.wikipedia.org/wiki/RC4

2

私のプロジェクトでは、次のコードを使用します。 「エンジン」と「配布」はライブラリによって提供されるものの1つになります。

#include <random> 
#include <functional> 
#include <iostream> 
... 
std::uniform_int_distribution<unsigned int> unif; 
std::random_device rd; 
std::mt19937 engine(rd()); 
std::function<unsigned int()> rnd = std::bind(unif, engine); 

std::cout << rnd() << '\n'; 
6

統一とは、すでに私が要約されます提供されたサンプルのいくつかの簡素化:

#include <random> 
#include <functional> 
#include <limits> 
#include <iostream> 

template<class Func> 
void print_min_mean_max(Func f) { 
    typedef decltype(f()) ret_t; 
    ret_t min = std::numeric_limits<ret_t>::max(), max = std::numeric_limits<ret_t>::min(); 
    uint64_t total = 0, count = 10000000; 
    for (uint64_t i = 0; i < count; ++i) { 
     auto res = f(); 
     min = std::min(min,res); 
     max = std::max(max,res); 
     total += res; 
    } 
    std::cout << "min: " << min << " mean: " << (total/count) << " max: " << max << std::endl; 
} 

int main() { 
    auto rnd1 = std::mt19937(std::random_device{}()); 
    auto rnd2 = std::default_random_engine(std::random_device{}()); 

    auto rnd3 = std::bind(std::uniform_int_distribution<int32_t>{}, std::mt19937(std::random_device{}())); 
    auto rnd4 = std::bind(std::uniform_int_distribution<int32_t>{std::numeric_limits<int32_t>::min(),std::numeric_limits<int32_t>::max()}, std::mt19937(std::random_device{}())); 

    print_min_mean_max(rnd1); 
    print_min_mean_max(rnd2); 
    print_min_mean_max(rnd3); 
    print_min_mean_max(rnd4); 
} 

が生成されます

// Good random seed, good engine 
auto rnd1 = std::mt19937(std::random_device{}()); 

// Good random seed, default engine 
auto rnd2 = std::default_random_engine(std::random_device{}()); 

// like rnd1, but force distribution to int32_t range 
auto rnd3 = std::bind(std::uniform_int_distribution<int32_t>{}, std::mt19937(std::random_device{}())); 

// like rnd3, but force distribution across negative numbers as well 
auto rnd4 = std::bind(std::uniform_int_distribution<int32_t>{std::numeric_limits<int32_t>::min(),std::numeric_limits<int32_t>::max()}, std::mt19937(std::random_device{}())); 

は、それから私は、デフォルトがどのように見えるかを確認するためにいくつかのテストを実行しました出力:

min: 234 mean: 2147328297 max: 4294966759 
min: 349 mean: 1073305503 max: 2147483423 
min: 601 mean: 1073779123 max: 2147483022 
min: -2147481965 mean: 178496 max: 2147482978 

私たちが見るように、mt19937とdefault_random_engineはデフォルトの範囲が異なりますので、uniform_int_distributionの使用をお勧めします。

また、符号付き整数型を使用する場合でも、デフォルトのuniform_int_distributionは[0、max_int](負ではない)です。完全な範囲が必要な場合は、明示的に範囲を指定する必要があります。

最後に、its important to remember this時にはこれらのようになります。

+2

メモ:64ビットバージョンの 'std :: mt19937':' std :: mt19937_64は呼び出しごとに64ビットのランダム性を返します。 'auto rnd5 = std :: mt19937_64(std :: random_device {}()); // min:4879020137534 mean:1655417118684 max:18446741225191893648' – Sean

+0

ところで、多くのディストリビューションとstd :: bind()を持つ同じ乱数エンジンを再利用することは安全ですか、それとも新しいディストリビューションにバインドする方がよいでしょうかエンジンインスタンス?これはどうですか: 'std :: mt19937_64 random = std :: mt19937_64(std :: random_device {}());' 'auto randomCardinality = std :: bind(std :: uniform_int_distribution (1、4)、random);' 'auto randomValue = std :: bind(std :: uniform_real_distribution (-1.0,1.0)、random);' – Xharlie

2

ここに行きます。ランダムな範囲で倍増:

// For ints 
// replace _real_ with _int_, 
// <double> with <int> and use integer constants 

#include <random> 
#include <iostream> 
#include <ctime> 
#include <algorithm> 
#include <iterator> 

int main() 
{ 
    std::default_random_engine rng(std::random_device{}()); 
    std::uniform_real_distribution<double> dist(-100, 100); //(min, max) 

    //get one 
    const double random_num = dist(rng); 

    //or.. 
    //print 10 of them, for fun. 
    std::generate_n( 
     std::ostream_iterator<double>(std::cout, "\n"), 
     10, 
     [&]{ return dist(rng);}); 
    return 0; 
} 
関連する問題