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:
The short answer is: there is no standard way to get the seed
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(); } };
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).
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)
Use srand() to set the seed. save the value you used as the seed.
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.
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;
}
};
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.
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.
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.
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:
- the same PRNG being used by the C library to expose both
rand()
andrandom()
interfaces, and - 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).
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...
来源:https://stackoverflow.com/questions/10198758/how-to-get-current-seed-from-c-rand