Ana Echavarria
Ana Echavarria

Reputation: 31

C++ random_shuffle is always giving the same results

The following call for random shuffle is always giving the same results for the vector v

#include <iostream>
#include <vector>
#include <algorithm>
#include <cstdlib>


int main()
{
    std::vector<int> v{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

    std::srand(time(0));
    std::random_shuffle(v.begin(), v.end());

    for (int i = 0; i < v.size(); ++i) {
        printf("%d ", v[i]); printf("\n");
    }

    printf("%d\n", std::rand() % 100);
}

I've tried compiling using

g++ -std=c++0x
g++ -std=c++11

But both give the same results every time so I don't really understand what's going on.

$./a.out
7 1 4 6 8 9 5 2 3 10 
26
$ ./a.out
7 1 4 6 8 9 5 2 3 10 
41
$ ./a.out
7 1 4 6 8 9 5 2 3 10 
39

Upvotes: 2

Views: 1518

Answers (3)

Amit
Amit

Reputation: 1130

Modern C++

It is not guarenteed in the standard that std::random_shuffle will relly on std::srand.

--

Footnote: std::random_shuffle is deprecated in C++14 and removed in C++17.

Since C++11 (the question is tagged with c++11), it is better to use std::shuffle and since C++20 to use std::ranges::shuffle, with an explicit randomness generator. Example:

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


int main() 
{
    std::vector<int> v{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

    std::random_device rd;
    std::mt19937 gen(rd()); // Mersenne Twister generator. 

//  std::shuffle(v.begin(), v.end(), gen);
    std::ranges::shuffle(v, gen); // (Since C++20)
    
    for (const auto& i : v) {
        std::cout << i << std::endl;
    }
}

Upvotes: 0

T.C.
T.C.

Reputation: 137315

OP's comment makes it clear that this is Clang and libc++ that they are using, not GCC/libstdc++.

A quick look at libc++'s random_shuffle implementation shows that it uses an object of type __rs_default as its source of randomness, and inspecting the implementation of __rs_default shows that it simply uses a default-constructed std::mt19937 object:

__rs_default::result_type
__rs_default::operator()()
{
    static mt19937 __rs_g;
    return __rs_g();
}

In other words, in this implementation srand has no effect whatsoever on the source of "randomness" used by the two-parameter version of random_shuffle. (Scary quotes because it always uses a fixed seed.) Note that random_shuffle is not required to use rand at all, so you can't expect srand to "work" in portable code anyway.

Use std::shuffle and the <random> facilities instead.

Upvotes: 8

Jonathan Wakely
Jonathan Wakely

Reputation: 171293

Firstly, -std=c++0x and -std=c++11 mean exactly the same thing, so testing both is pointless.

You didn't provide a complete program (please read https://stackoverflow.com/help/mcve next time) so I guessed at the rest of your code, and I tried this:

#include <iostream>
#include <vector>
#include <algorithm>
#include <stdlib.h>

using namespace std;

int main()
{
  vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
  srand(time(0));
  random_shuffle(v.begin(), v.end());

  for (int i : v)
    std::cout << i << ' ';
  std::cout << std::endl;
}

I get different results every second:

tmp$ ./a.out
2 1 8 5 9 7 6 3 10 4 
tmp$ ./a.out
10 7 6 3 1 8 9 4 5 2 
tmp$ ./a.out
4 7 3 6 5 8 1 9 10 2 
tmp$ ./a.out
4 7 3 6 5 8 1 9 10 2 
tmp$ ./a.out
4 7 3 6 5 8 1 9 10 2 
tmp$ ./a.out
10 2 6 3 9 4 5 7 8 1 
tmp$ ./a.out
10 2 6 3 9 4 5 7 8 1 
tmp$ ./a.out
10 2 6 3 9 4 5 7 8 1 
tmp$ ./a.out
2 1 3 7 5 8 9 6 4 10 

The times when it produces the same result are because the number of seconds returned by time(0) is the same, and so the seed for the rand() function is the same, and so the results are the same. If you wait a second so that time(0) returns a different value you should get a different random shuffle of the elements.

If the code you are running is not the same as mine you might get different results, but we can't possibly explain the results because you didn't show us your code.

Upvotes: 4

Related Questions