2013-01-08 16 views
10

可能性の重複:
How to make sure that std::random_shuffle always produces a different result?のstd :: random_shuffleは、同じ結果を生成するたびに

は、私は配列を持っていると私はそれをシャッフルしたい、私が使用します。

answerPositionArray[0] = 100; 
answerPositionArray[1] = 400; 
answerPositionArray[2] = 800; 
std::random_shuffle(answerPositionArray, answerPositionArray + 2); 

しかし、プログラムを実行するたびに同じシャッフルが出ます(400,800,100)。シャッフルをdifferenにする方法はありますか毎回?例えば。など、その後初めて100、800、400 800、400、100

おかげで

+17

私は見ているものから、 'std :: srand(std :: time(0))'を忘れてしまいました。 – Rapptz

+0

コードにその行をどこに入れる必要がありますか? – panthro

+2

@ user1013512ランダムに電話する前に – lcs

答えて

21

C++乱数が真の乱数ではありません - 彼らはシードと呼ばれる初期値から生成されています。シードを設定しない場合、常に同じになるので、生成されるシーケンスは変更されません。 std::random_shuffleは乱数の生成に依存しているため、このように動作します。

どのようにシードを設定するのですか?

srand(time(0)); 

乱数を使用する関数を呼び出す前。シードを現在の時間(秒)に設定します。適切なヘッダファイルを追加することを忘れないでください。

+0

Iveがそれを追加しました:answerPositionArray [0] = 100; \t answerPositionArray [1] = 400; \t answerPositionArray [2] = 800; \t std :: srand(std :: time(0)); \t std :: random_shuffle(answerPositionArray、answerPositionArray + 2); – panthro

+2

動作しません。 – panthro

+0

テストの間に少なくとも1秒待っていましたか? – KCH

26

std::random_shuffle(b,e)は、インプリメンテーションによって定義されたランダム性のソースを使用するため、移植可能に制御することはできません。通常、実装はstd::rand()を使用していますので、std::srand()を使用してrngをシードすることがよくあります。

// not portable, depends on implementation defined source of randomness in random_shuffle 
std::srand(some_seed); 
std::random_shuffle(answerPositionArray, answerPositionArray+size); 

第三パラメータとして、乱数発生器を取るstd::random_shuffle()のオーバーロードがあります。このフォームを使用して、ランダム化のソースを定義して、それをシードすることができます。

struct RNG { 
    int operator() (int n) { 
     return std::rand()/(1.0 + RAND_MAX) * n; 
    } 
}; 

std::srand(seed); 
std::random_shuffle(answerPositionArray, answerPositionArray+size, RNG()); 

C++ 11あなたがC++ 11台の<random>発電機を使用することができ、するUniformRandomNumberGeneratorを取る別のアルゴリズムstd::shuffleが導入されています。あなたのご意見は、問題があることであったことを示している

std::random_device r; 
std::seed_seq seed{r(), r(), r(), r(), r(), r(), r(), r()}; 
std::mt19937 eng(seed); 

std::shuffle(std::begin(answerPositionArray), std::end(answerPositionArray), eng); 

をあなたは最初の2つの要素をシャッフルしていただけで、最後の要素には触れていなかったということは、配列全体をシャッフルしていないことでした。

これはあなたのコードのように、マジックナンバーを使用する方法の良いデモです:

std::random_shuffle(answerPositionArray, answerPositionArray + 2); 
                  ^
                   | 
               magic number -- 

は、エラーが発生しやすくすることができます。代わりに、そのような値とは無関係に動作するコードを記述するようにしてください。

// trick for getting an array size 
template<typename T, int N> int array_size(T (&)[N]) { return N; } 

int answerPositionArray[] = {100, 400, 800}; 

std::random_shuffle(answerPositionArray, 
        answerPositionArray + array_size(answerPositionArray)); 

それとも、C++ 11を使用することができたら、アレイ上のstd::beginstd::endを使用することができます。

std::random_shuffle(std::begin(answerPositionArray), std::end(answerPositionArray)); 

それとも、上記の配列を使用してC++ 03 beginend機能を自分で実装することができますサイズトリック:

template<typename T, int N> T *begin(T (&a)[N]) { return a; } 
template<typename T, int N> T *end(T (&a)[N]) { return a + N; } 

これらの方法では、配列サイズにマジックナンバーを使用する必要がなくなりますあなたが間違った値を間違って使用する可能性が低いコードを書いたり変更したりします。

+0

C++を使用していません11 – panthro

+4

@ user1013512:投稿全体を読んでください。彼はC++ 98/03とC++ 11の両方のソリューションを提供しています。 –

+0

@ user1013512次に、私が言及する 'std :: random_shuffle'の2番目のオーバーロードが必要です。あるいは、あなたが気にする実装が 'std :: rand'を使用していることを確認できれば、その実装の詳細に依存して' std :: srand() 'を使うことができます。 – bames53

関連する問題