How to get current seed from C++ rand()?
Asked Answered
J

8

21

I generate a few thousand object in my program based on the C++ rand() function. Keeping them in the memory would be exhaustive. Is there a way to copy the CURRENT seed of rand() at any given time? This would give me the opportunity to store ONLY the current seeds and not full objects. (thus I could regenerate those objects, by regenerating the exact same sub-sequences of random numbers)

An exhaustive solution is storing the full sequence of random numbers given by rand() - doesn't worth it. Another would be solution is to implement my own class for randomized numbers.

Google gave me no positive clues. There are hundreds of articles teaching the basics of rand and srand, and I couldn't find the specific ones.

Does anyone know other random number generators with implemented seed-stealer?


Thank you for your fast answers! There are more possible answers/solutions to this question, so I made a list of your answers here.

SOLUTIONS:

  1. The short answer is: there is no standard way to get the seed

  2. The closest possible workaround is to save the INITIAL seed in the beginning, and count how many times you call the rand() function. I marked this as solution because it works on the current std::rand() function of every compiler (and this was the main question about). I've benchmarked my 2.0 GHz CPU, and found that I can call&count rand() 1,000,000,000 times in 35 seconds. This might sound good, but I have 80,000 calls to generate one object. This restricts the number of generations to 50,000 because the size of unsigned long. Anyway, here is my code:

    class rand2
    {
       unsigned long n;
    
       public:
    
       rand2 () : n(0) {}
    
       unsigned long rnd()
       {
          n++;
          return rand();
       }
       // get number of rand() calls inside this object
       unsigned long getno ()
       {
          return n;
       }
       // fast forward to a saved position called rec
       void fast_forward (unsigned long rec)
       {
          while (n < rec) rnd();
       }
    };
    
  3. Another way is to implement your own Pseudo-random number generator, like the one Matteo Italia suggested. This is the fastest, and possibly the BEST solution. You're not restricted to 4,294,967,295 rand() calls, and don't need to use other libraries either. It's worth mentioning that different compilers have different generators. I've compared Matteo's LCG with rand() in Mingw/GCC 3.4.2 and G++ 4.3.2. All 3 of them were different (with seed = 0).

  4. Use generators from C++11 or other libraries as Cubbi, Jerry Coffin and Mike Seymour suggested. This is the best idea, if you're already working with them. Link for C++11 generators: http://en.cppreference.com/w/cpp/numeric/random (there are some algorithm descriptions here too)

Jadeite answered 17/4, 2012 at 20:37 Comment(3)
If in solution 2 only the count limit is the problem you can add another unsigned long counter to count the overflows. This would effectively double the bit size of your counter and can, of course, further extended.Ornithischian
BTW, it's nice of you to add a solution summary (good old usenet tradition?).Ornithischian
Heh, no. I actually had to google what usenet means :). Just thought it would be nice to give some feedback, that the answers were useful.Jadeite
T
5

Use srand() to set the seed. save the value you used as the seed.

http://cplusplus.com/reference/clibrary/cstdlib/srand/

Tristichous answered 17/4, 2012 at 20:42 Comment(1)
That's fine if you want to recreate the entire sequence, but not if you want to extract the seed at any given time.Firehouse
V
13

Does anyone know other random number generators with implemented seed-stealer

All standard C++11 random number generators (also available in TR1 and in Boost) offer this functionality. You can simply copy the generator objects or serialize/deserialize them.

Velleman answered 17/4, 2012 at 20:43 Comment(0)
N
8

There's no standard way to obtain the current seed (you can only set it via srand), but you can reimplement rand() (which is usually a linear congruential generator) by yourself in a few lines of code:

class LCG
{
private:
    unsigned long next = 1;
public:

    LCG(unsigned long seed) : next(seed) {}

    const unsigned long rand_max = 32767

    int rand()
    {
        next = next * 1103515245 + 12345;
        return (unsigned int)(next/65536) % 32768;
    }

    void reseed(unsigned long seed)
    {
        next = seed;
    }

    unsigned long getseed()
    {
        return next;
    }
};
Novena answered 17/4, 2012 at 20:43 Comment(0)
T
5

Use srand() to set the seed. save the value you used as the seed.

http://cplusplus.com/reference/clibrary/cstdlib/srand/

Tristichous answered 17/4, 2012 at 20:42 Comment(1)
That's fine if you want to recreate the entire sequence, but not if you want to extract the seed at any given time.Firehouse
P
5

The random number generation classes in C++11 support operator<< to store their state (mostly the seed) and operator>> to read it back in. So, basically, before you create your objects, save the state, then when you need to re-generate same sequence, read the state back in, and off you go.

Parquetry answered 17/4, 2012 at 20:43 Comment(0)
F
4

rand() does not offer any way to extract or duplicate the seed. The best you can do is store the initial value of the seed when you set it with srand(), and then reconstruct the whole sequence from that.

The Posix function rand_r() gives you control of the seed.

The C++11 library includes a random number library based on sequence-generating "engines"; these engines are copyable, and allow their state to be extracted and restored with << and >> operators, so that you can capture the state of a sequence at any time. Very similar libraries are available in TR1 and Boost, if you can't use C++11 yet.

Firehouse answered 17/4, 2012 at 20:46 Comment(0)
W
1

Is there a way to copy the CURRENT seed of rand() at any given time?

What follows is an implementation-specific way to save and restore the pseudo-random number generator (PRNG) state that works with the C library on Ubuntu Linux (tested on 14.04 and 16.04).

#include <array>
#include <cstdlib>
#include <iostream>

using namespace std;

constexpr size_t StateSize = 128;
using RandState = array<char, StateSize>;

void save(RandState& state) {
    RandState tmpState;
    char* oldState = initstate(1, tmpState.data(), StateSize);
    copy(oldState, oldState + StateSize, state.data());
    setstate(oldState);
}

void restore(RandState& state) {
    setstate(state.data());
}

int main() {
    cout << "srand(1)\n";

    srand(1);

    cout << "  rand(): " << rand() << '\n';
    cout << "  rand(): " << rand() << '\n';
    cout << "  rand(): " << rand() << '\n';
    cout << "  rand(): " << rand() << '\n';
    cout << "  rand(): " << rand() << '\n';
    cout << "  rand(): " << rand() << '\n';
    cout << "  rand(): " << rand() << '\n';
    cout << "  rand(): " << rand() << '\n';

    cout << "srand(1)\n";

    srand(1);

    cout << "  rand(): " << rand() << '\n';
    cout << "  rand(): " << rand() << '\n';
    cout << "  rand(): " << rand() << '\n';
    cout << "  rand(): " << rand() << '\n';

    cout << "save()\n";

    RandState state;
    save(state);

    cout << "  rand(): " << rand() << '\n';
    cout << "  rand(): " << rand() << '\n';
    cout << "  rand(): " << rand() << '\n';
    cout << "  rand(): " << rand() << '\n';

    cout << "restore()\n";

    restore(state);

    cout << "  rand(): " << rand() << '\n';
    cout << "  rand(): " << rand() << '\n';
    cout << "  rand(): " << rand() << '\n';
    cout << "  rand(): " << rand() << '\n';
}

This relies on:

  1. the same PRNG being used by the C library to expose both rand() and random() interfaces, and
  2. some knowledge about the default initialization of this PRNG in the C library (128 bytes state).

If run, this should output:

srand(1)
  rand(): 1804289383
  rand(): 846930886
  rand(): 1681692777
  rand(): 1714636915
  rand(): 1957747793
  rand(): 424238335
  rand(): 719885386
  rand(): 1649760492
srand(1)
  rand(): 1804289383
  rand(): 846930886
  rand(): 1681692777
  rand(): 1714636915
save()
  rand(): 1957747793
  rand(): 424238335
  rand(): 719885386
  rand(): 1649760492
restore()
  rand(): 1957747793
  rand(): 424238335
  rand(): 719885386
  rand(): 1649760492

This solution can help in some cases (code that can't be changed, reproducing execution for debugging purpose, etc...), but it is obviously not recommended as a general one (e.g. use C++11 PRNG which properly support this).

Westminster answered 15/9, 2016 at 22:50 Comment(0)
S
0

You could try saving the value that you used to seed right before (or after) the srand.

So, for example:

int seed = time(NULL);
srand(time(NULL));

cout << seed << endl;
cout << time(NULL);

The two values should be the same.

Samal answered 17/4, 2012 at 20:56 Comment(0)
G
-1

I would recommend you to use the Mersenne Twister Pseudo-Random Number Generator. It is fast and offer very good random numbers. You can seed the generator in the constructor of the class very simply by

unsigned long rSeed = 10;
MTRand myRandGen(rSeed);

Then you just need to store somewhere the seeds you used to generate the sequences...

Gravimetric answered 21/2, 2014 at 4:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.