2017-02-21 13 views
-1

私の目標は、ランダムな値を持つベクトルのベクトルの各ベクトルの各要素を満たすことです。次のコードを検討してください:イテレータを使用するときにランダムジェネレータを再配置する必要があるのはなぜですか?

#include <algorithm> 
#include <iostream> 
#include <random> 
#include <vector> 


typedef std::vector<int> IntVect; 
typedef std::vector<IntVect> Grid; 


void fillRandom(Grid& grid, int lo, int hi); 


int main(int argc, const char * argv[]) { 

    Grid grid { Grid(5, IntVect (5)) }; 

    fillRandom(grid, 0, 10); 

    for (auto& row : grid) { 
     for (auto& i : row) { 
      std::cout << i << " "; 
     } 
     std::cout << "\n"; 
    } 
    return 0; 
} 
// fillRandom v1 
void fillRandom(Grid& grid, int lo, int hi) { 

    // Init Random engine 
    std::random_device rnd_device; 
    std::mt19937 generator { rnd_device() }; 
    std::uniform_int_distribution<int> distr(lo, hi); 
    auto dice = std::bind(distr, generator); 

    Grid::iterator i { grid.begin() }; 
    for (; i != grid.end(); ++i) { 
     std::generate(i->begin(), i->end(), dice); 
     generator.seed(rnd_device());    // reseed 
     dice = std::bind(distr, generator); 
    } 
    return; 
} 

fillRandomで、私はgridの各要素のための発電機を再シードする必要があります。

7 5 8 1 9 
7 5 8 1 9 
7 5 8 1 9 
7 5 8 1 9 
7 5 8 1 9 

:それ以外の場合、出力は次のように、gridの各要素について同じになります。私はfillRandomを変更する場合は、:

// fillRandom v2 
void fillRandom(Grid& grid, int lo, int hi) { 

    // Init Random engine as above 

    for (auto& row : grid) 
     for (auto& i : row) 
      i = dice(); 
    return; 
} 

私はgridの各vectorのための発電機を再シードせずに期待される結果を取得します。

fillRandomdice()の第2のバージョンでは、各ベクトルの各要素が呼び出され、結果としてgridがランダムな値で埋められます。しかし、最初のバージョンはまったく同じことを行う必要があります。しかし明らかにそうではありません。ここでの違いは何ですか?

は、なぜ私はstd::generateとイテレータを使用する場合、すべてのベクトルのための乱数発生器を再シードする必要がありますか?この行動を理解するのを助けてください。

答えて

3

ラインstd::generate(i->begin(), i->end(), dice);は、そのコピーを作成し、値によってdiceをとります。バインドされた引数もコピーされます。これにより、元の状態を変更することなく、毎回同じジェネレータとディストリビューションをコピーすることになります。各反復は同じ状態から始まります。

2番目の例では、単にループ内でdiceを呼び出すと、ジェネレータとディストリビューションの単一インスタンスに値が生成され、結果として内部状態が前進し、次の繰り返しで異なる値になります。

ではなく、lamdbaでそれを試してみてください。

// fillRandom v1 
void fillRandom(Grid& grid, int lo, int hi) { 

    // Init Random engine 
    std::random_device rnd_device; 
    std::mt19937 generator{ rnd_device() }; 
    std::uniform_int_distribution<int> distr(lo, hi); 
    auto dice = [&generator, &distr]() { return distr(generator); }; 

    Grid::iterator i{ grid.begin() }; 
    for (; i != grid.end(); ++i) { 
     std::generate(i->begin(), i->end(), dice); 
    } 
    return; 
} 
+1

これはラムダの代わりに動作し、より簡潔です: 'auto dice = std :: bind(distr、std :: ref(generator));' – zett42

関連する問題