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

99封情书 提交于 2019-11-30 08:25:24

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

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

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:

  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).

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...

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!