3

The following code snippet randomly shuffles an STL array of integers -- it works correctly on both Ubuntu and Red Hat. However, on my Mac OS X box, the array shuffles to the same order every time. The second section of the code prints the output of the random number generator, which is decidedly not random.

Am I doing something wrong, or did something change when I upgraded my OS X/XCode suite? Either way, is this a security hole? ... certainly a lot of legacy code that may have be used to generate random numbers could look like this, and suddenly be no longer random.

Thoughts?

The code (try it yourself):

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

using namespace std;

int main()
{

    //First, let's initialize, shuffle, and print a random vector.
    vector<int> myOrder;

    for(int i = 0; i < 10; i++)
            myOrder.push_back(i);

    uint seed = time(NULL);
    std::srand( seed );
    std::random_shuffle(myOrder.begin(), myOrder.end());


    for(vector<int>::iterator it = myOrder.begin(); it != myOrder.end(); it++)
            cout << *it << "\t";



    //Let's check the output of the PRNG:
    cout << "\nMy seed is: " << seed << "\n==================\n";

    for(int i = 0; i < 10; i++)
            cout << rand() << "\t";

    cout << endl;
}

Output from 3 runs on Ubuntu:

4   3   6   2   7   1   9   5   0   8   
My seed is: 1395151370
==================
38394197    1995358147  65276563    2013488432  1137737660  1255414699  924908498   309981427   1799367638  1337198287  

 2  4   7   9   6   8   5   3   0   1   
My seed is: 1395151371
==================
1281137856  2008486108  1477643146  1786210280  166055115   1227183121  819984618   1762177356  207844974   1730642206  

3   6   0   5   7   8   1   4   2   9   
My seed is: 1395151372
==================
397185149   960257000   1833707166  510257843   283547169   1218814437  1818880205  1086171377  1860201155  12516048

And now, output from 3 runs on OS X:

6   0   3   5   7   8   4   1   2   9   
My seed is: 1395151529
==================
2085289957  535188259   1247555377  1780375578  1882685795  1276101667  521534680   1552603353  530759174   1969851427  


6   0   3   5   7   8   4   1   2   9   
My seed is: 1395151530
==================
2085306764  817663508   722721803   617835589   879311078   1746312939  622562224   862970584   1989537097  1829605489  


6   0   3   5   7   8   4   1   2   9   
My seed is: 1395151531
==================
2085323571  1100138757  197888229   1602779247  2023420008  69040564    723589768   173337815   1300831373  1689359551  
  • 3
    It's recommended to use `std::shuffle` instead. That overload of `std::random_shuffle` is about to be deprecated, and `rand` can be replaced with the utilities in ``. – chris Mar 18 '14 at 14:13
  • Are you using g++ on both or clang on OSX? – cheezsteak Mar 18 '14 at 14:16
  • 3
    `std::random_shuffle` is not required to use `rand()`. So it could be that your standard library on Mac OSX is calling something different, therefore setting the `rand` seed has no effect. – juanchopanza Mar 18 '14 at 14:16
  • [`rand()` Considered Harmful](http://channel9.msdn.com/Events/GoingNative/2013/rand-Considered-Harmful) – fredoverflow Mar 18 '14 at 14:19
  • Chris's answer works well. Code can be found here: http://www.cplusplus.com/reference/algorithm/shuffle/ though you have to compile with -std=c++11 – user3433072 Mar 18 '14 at 14:36

1 Answers1

5
template<class RandomIt> void random_shuffle(RandomIt first, RandomIt last);
// deprecated in C++14

uses an implementation-defined source of randomness that cannot be controlled.

Implementations often use std::rand, so calling std::srand to seed the prng could work but it's not portable.

You can use a random_shuffle that takes a third parameter:

C++11 (example from http://en.cppreference.com)

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

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

    std::random_device rd;
    std::mt19937 g(rd());

    std::shuffle(v.begin(), v.end(), g);

    copy(v.begin(), v.end(), std::ostream_iterator<int>(std::cout, " "));
    std::cout << "\n";
}

or

C++03

...
int my_random(int i) { return std::rand() % i;}

std::srand(seed);
std::random_shuffle(myOrder.begin(), myOrder.end(), my_random);
...
manlio
  • 18,345
  • 14
  • 76
  • 126
  • First, I am seeding std:srand in my code, so it is a problem with the PRNG itself. Also, your C++03 solution seems commonly recommended-against. See the article linked-to by Paul R. The C++-11 recommendation by Chris works well enough. – user3433072 Mar 18 '14 at 14:35
  • 1
    Your question hasn't the C++11 tag so there are two examples. The first is probably better and it's not std::rand based but **requires** C++11 (std::shuffle and the random header). The second works with C++03 but requires rand/srand – manlio Mar 18 '14 at 14:40
  • Yup, sorry about that. – user3433072 Mar 18 '14 at 14:42