问题
I am currently running a multithreading simulation application with 8+ pipes (threads). These pipes run a very complex code that depends on a random sequence generated by a seed. The sequence is then boiled down to a single 0/1.
I want this "random processing" to be 100% deterministic after passing a seed to the processing pipe from the main thread. So, I can replicate the results in a second run.
So, for example: (I have this coded and it works)
Pipe 1 -> Seed: 123 -> Result: 0
Pipe 2 -> Seed: 123 -> Result: 0
Pipe 3 -> Seed: 589 -> Result: 1
The problem arises when I need to run 100M or more of these processes and then average the results. It may be the case only 1 of the 100M is a 1, and the rest are 0.
As it is obvious, I cannot sample 100M random values with 32bit seeds feeding to srand()
.
Is it possible to seed with a 64bit seed in VS2010 to srand(), or use a equivalent approach?
Does rand() repeat itself after 2^32 or does not (has some inner hidden state)?
Thanks
回答1:
You can use C++11's random facilities to generate random numbers of a given size and seed size, though the process is a bit too complicated to summarize here.
For example, you can construct an std::mersenne_twister<uint64_t, ...>
and seed it with a 64-bit integer, then acquire random numbers within a specified distribution, which seems to be what you're looking for.
回答2:
A simple 64-bit LCG should meet your needs. Bit n (counting from the least significant as bit 1) of an LCG has period at most (and, if parameters are chosen correctly, then exactly) 2^n, so avoid using the lower bits if you don't need them, and/or use a tempering function on the output. A sample implementation can be found in my answer to another question here:
https://stackoverflow.com/a/19083740/379897
And reposted:
static uint32_t temper(uint32_t x)
{
x ^= x>>11;
x ^= x<<7 & 0x9D2C5680;
x ^= x<<15 & 0xEFC60000;
x ^= x>>18;
return x;
}
uint32_t lcg64_temper(uint64_t *seed)
{
*seed = 6364136223846793005ULL * *seed + 1;
return temper(*seed >> 32);
}
回答3:
you could use an XOR SHIFT psuedorandom number generator
It is fast and works a treat - this is the actual generation part from my implementation class of it. I found the information on this algorithm in a wikipedia search on psuedorandom number generators...
uint64_t XRS_64::generate(void)
{
seed ^= seed >> 12; // a
seed ^= seed << 25; // b
seed ^= seed >> 27; // c
return seed * UINT64_C(2685821657736338717);
}
it is fast and for initialisation you do that inside the constructor
XRS_64::XRS_64()
{
seed = 6394358446697381921;
}
seed is an unsigned int 64 bit variable and it is declared inside the class.
class XRS_64
{
public:
XRS_64();
~XRS_64();
void init(uint64_t newseed);
uint64_t generate();
private :
uint64_t seed; /* The state must be seeded with a nonzero value. */
};
回答4:
I can't answer your questions, but if you find out you can't do what you want, you can implement your own pseudo-random algorithm generator which takes a uint64_t
as a seed.
There are better algorithms for this purpose if you want some more serious generator (for cryptography purposes, for instance), but LCG is the easiest I've seen to be implemented.
EDIT
Actually you cannot use a 64-bit seed for the rand()
function. You will have to go for your own. In this Wikipedia table there some parameters used by MMIX Donald Knuth to implement it. Be aware that depending on the parameters you use, your random number generator period will have a much lesser value than 2^64 and because of the multiplications, you may need a Big Number library to handle the math operations.
来源:https://stackoverflow.com/questions/19734365/64-bits-seeds-for-random-generators