Mersenne Twister is relatively slow because it gives you very high quality random numbers. For most applications (like this one), you don't really need that high quality, and can get away with faster generators.krismchess wrote:Hi Mar,
FastRandom - is really *FAST*. It goes through in 2 seconds time (consistent when I ran it for a dozen of times). Can you post some theory behind this - how it works etc.?
Also Do you allow me to use your FastRandom code in my chess engine & I'll provide this forum reference & your name in the code comments & README notes.
Many thanks.
krismchess wrote:I will try this one from Bob Jenkins' pages & your FastRandom.
Meanwhile I tried to use a KISS PRNG & the C++ <random> lib using random_device, uniform_int_distribution & mt19937_64 and found the <random> lib is consistent with 3 seconds while KISS PRNG is taking a bit longer. Full code below:Code: Select all
class Random { private: std::random_device rd; std::mt19937_64 mt; std::uniform_int_distribution<uint64_t> dist; public: Random() : rd(),mt(rd()),dist() { } uint64_t next() { return dist(mt); } }; // A KISS PRNG typedef uint64_t uint64; uint64 x = uint64(123456789123); uint64 y = uint64(987654321987); uint64 z1 = uint64(43219876); uint64 c1 = uint64(6543217); uint64 z2 = uint64(21987643); uint64 c2 = uint64(1732654); uint64 rand64(); uint64 rand64() { uint64 t; x = uint64(1490024343005336237) * x + 123456789; y ^= y << 21; y ^= y >> 17; y ^= y << 30; /* Do not set y=0! */ t = uint64(4294584393) * z1 + c1; c1 = t >> 32; z1 = t; t = uint64(4246477509) * z2 + c2; c2 = t >> 32; z2 = t; return x + y + z1 + ((uint64)z2 << 32); /* Return 64-bit result */ }mar wrote:Bob Jenkins' pages: http://burtleburtle.net/bob/rand/smallprng.htmlkrismchess wrote:Where can I get a KISS PRNG examples?
And how should I find the seed numbers to them?
Alternatively you could use mine (public domain):
ULong = uint64_t, Byte = uint8_tCode: Select all
class FastRandom { inline ULong Rotate( ULong v, Byte s ) { return (v >> s) | (v << (64-s)); } public: FastRandom() { Seed(0); } // generate next 64-bit random number inline ULong Next() { ULong tmp = keys[0]; keys[0] += Rotate( keys[1] ^ 0xc5462216u ^ ((ULong)0xcf14f4ebu<<32), 1 ); return keys[1] += Rotate( tmp ^ 0x75ecfc58u ^ ((ULong)0x9576080cu<<32), 9 ); } void Seed( ULong val ) { keys[0] = keys[1] = val; for ( Int i=0; i<64; i++ ) { Next(); } } private: ULong keys[2]; };
Passes dieharder tests, used by a couple of people for various things (a friend used it as part of a fast mesh simplification algorithm to choose edge collapses)
keys is IV and you can simply seed the internal state with std:: random generators/whatever and choose the one which works best for you.
Performance depends on the ability of your compiler to fold the rotations; IIRC clang had some problems, but I don't remember exactly.Code: Select all
I personally always stick with MT unless profiling shows that it's a bottleneck. I haven't encountered one yet (not just in chess, but in everything I have programmed). I guess this is one such case, though, if you insist on not hard-coding.
I personally just hard code them.