I need to generate a deterministic (i.e. repeatable) sequence of pseudo-random numbers given an initial seed and select the nth item from that sequence.
If JavaScript's random function was seedable, I could just do:
function randomNth(seed, seq)
{
var r;
Math.randomSeed(seed);
for (var i = 0; i++ < seq; i++)
{
r = Math.random();
}
return r;
}
However, it's not, and alternative, seedable PRNGs look to be a little slow; asking for the 250th number would be expensive.
I think a hash is what I want here, perhaps something like md5(seed + seq) % max
but JavaScript doesn't have md5() and if I'm doing it in code there's probably a better choice of hash.
I'd like a function where
x = randomNth(seed, seq, maxVal) // x is int && x >= 0 && x < maxVal
or, ideally
x = randomNth(seed, seq) // x >= 0 && x < 1, same as Math.random()
Other requirements:
- must run in node.js and in a browser
- numbers should be statistically random (or close enough as the period will be small)
- should be O(1) and reasonably performant
There are some good int -> int hashing functions on this page you can use one of them.
function hash(a)
{
a = (a+0x7ed55d16) + (a<<12);
a = (a^0xc761c23c) ^ (a>>19);
a = (a+0x165667b1) + (a<<5);
a = (a+0xd3a2646c) ^ (a<<9);
a = (a+0xfd7046c5) + (a<<3);
a = (a^0xb55a4f09) ^ (a>>16);
if( a < 0 ) a = 0xffffffff + a;
return a;
}
var seed = 26254;
var index = 250;
alert( hash( seed + index ) );
In the end I used a suggestion from a (non-SO) friend. I went with CRC32() as this is extremely fast and gives decently random values.
return crc32(seq + seed) % maxVal;
A run of eight million produced the following distribution for maxVal = 8:
0 999998
1 999998
2
1000007
3
1000003
4
1000001
5
1000003
6
999992
7
999998
I also ran "Marsaglia's famous "Die Hard" battery of tests" mentioned in the Donald Knuth page Hans mentioned, the results of which are here: CRC32() for random numbers Diehard results. The short version is that it fails miserably (for such a small amount of test data), but it's still good enough for my needs where it is generating numbers in a small range.
Donald Knuth may be of help : http://www-cs-faculty.stanford.edu/~uno/news02.html#rng
Use this Mersenne Twister implementation in javascript.