Seeding the random number generator in Javascript


Is it possible to seed the random number generator (Math.random) in Javascript?

No, it is not, but it's fairly easy to write your own generator, or better yet use an existing one. Check out: this related question.

Also, see David Bau's blog for more information on seeding.


NOTE: Despite (or rather, because of) succinctness and apparent elegance, this algorithm is by no means a high-quality one in terms of randomness. Look for e.g. those listed in this answer for better results.

(Originally adapted from a clever idea presented in a comment to another answer.)

var seed = 1;
function random() {
    var x = Math.sin(seed++) * 10000;
    return x - Math.floor(x);
}

You can set seed to be any number, just avoid zero (or any multiple of Math.PI).

The elegance of this solution, in my opinion, comes from the lack of any "magic" numbers (besides 10000, which represents about the minimum amount of digits you must throw away to avoid odd patterns - see results with values 10, 100, 1000). Brevity is also nice.

It's a bit slower than Math.random() (by a factor of 2 or 3), but I believe it's about as fast as any other solution written in JavaScript.


I've implemented a number of good, short and fast Pseudorandom number generator (PRNG) functions in plain JavaScript. All of them can be seeded and provide good quality numbers.

First of all, take care to initialize your PRNGs properly. Most of the generators below have no built-in seed generating procedure (for sake of simplicity), but accept one or more 32-bit values as the initial state of the PRNG. Similar seeds (e.g. a simple seed of 1 and 2) can cause correlations in weaker PRNGs, resulting in the output having similar properties (such as randomly generated levels being similar). To avoid this, it is best practice to initialize PRNGs with a well-distributed seed.

Thankfully, hash functions are very good at generating seeds for PRNGs from short strings. A good hash function will generate very different results even when two strings are similar. Here's an example based on MurmurHash3's mixing function:

function xmur3(str) {
    for(var i = 0, h = 1779033703 ^ str.length; i < str.length; i++)
        h = Math.imul(h ^ str.charCodeAt(i), 3432918353),
        h = h << 13 | h >>> 19;
    return function() {
        h = Math.imul(h ^ h >>> 16, 2246822507);
        h = Math.imul(h ^ h >>> 13, 3266489909);
        return (h ^= h >>> 16) >>> 0;
    }
}

Each subsequent call to the return function of xmur3 produces a new "random" 32-bit hash value to be used as a seed in a PRNG. Here's how you might use it:

// Create xmur3 state:
var seed = xmur3("apples");
// Output four 32-bit hashes to provide the seed for sfc32.
var rand = sfc32(seed(), seed(), seed(), seed());

// Output one 32-bit hash to provide the seed for mulberry32.
var rand = mulberry32(seed());

// Obtain sequential random numbers like so:
rand();
rand();

Alternatively, simply choose some dummy data to pad the seed with, and advance the generator a few times (12-20 iterations) to mix the initial state thoroughly. This is often seen in reference implementations of PRNGs, but it does limit the number of initial states.

var seed = 1337 ^ 0xDEADBEEF; // 32-bit seed with optional XOR value
// Pad seed with Phi, Pi and E.
// https://en.wikipedia.org/wiki/Nothing-up-my-sleeve_number
var rand = sfc32(0x9E3779B9, 0x243F6A88, 0xB7E15162, seed);
for (var i = 0; i < 15; i++) rand();

Another thing to note is that these are all 32-bit generators, which means everything is bound by 32-bit operations, simulating 32-bit C code. 64-bit generators exist, and are usually the better choice in languages such as C/C++, but JS is not optimized for 64-bit math. JS has a limit of 53-bit integers, but bitwise operations are limited to 32-bit integers, so even efficient usage of all 53 bits is tricky. Luckily, 32-bit operations get an optimization boost in modern JS engines. That is likely why Baagøe's supposedly super-fast 53-bit Alea generator ends up slower than these implementations.

Now, onward to the the generators. (I maintain the full list with references here)


sfc32

This generator is part of the PractRand random number testing suite, of which it passes without issue. PractRand is purportedly even more stringent than TestU01. sfc32 has a 128-bit state and is also very fast in JS (xoshiro128** is slightly faster, but has some linearity issues). sfc32 is probably my PRNG of choice.

function sfc32(a, b, c, d) {
    return function() {
      a >>>= 0; b >>>= 0; c >>>= 0; d >>>= 0; 
      var t = (a + b) | 0;
      a = b ^ b >>> 9;
      b = c + (c << 3) | 0;
      c = (c << 21 | c >>> 11);
      d = d + 1 | 0;
      t = t + d | 0;
      c = c + t | 0;
      return (t >>> 0) / 4294967296;
    }
}

Mulberry32

Mulberry32 is a simple generator, but is quite fast and has good quality (author states it passes all tests of gjrand). I would recommend this if you just need a simple but decent PRNG.

It has a state of 32-bits and a full period of 232. Ideal if you only want to seed with one 32-bit integer and don't care about the birthday problem. There is 4.3 billion possible states in Mulberry32 compared to the 340 undecillion in sfc32/xoshiro128**.

function mulberry32(a) {
    return function() {
      var t = a += 0x6D2B79F5;
      t = Math.imul(t ^ t >>> 15, t | 1);
      t ^= t + Math.imul(t ^ t >>> 7, t | 61);
      return ((t ^ t >>> 14) >>> 0) / 4294967296;
    }
}

xoshiro128**

As of May 2018, xoshiro128** is the new member of the Xorshift family. It offers a 128-bit state, and is super fast.

function xoshiro128ss(a, b, c, d) {
    return function() {
        var t = b << 9, r = a * 5; r = (r << 7 | r >>> 25) * 9;
        c ^= a; d ^= b;
        b ^= c; a ^= d; c ^= t;
        d = d << 11 | d >>> 21;
        return (r >>> 0) / 4294967296;
    }
}

This PRNG is the latest by Blackman/Vigna who also wrote the PRNGs xorshift128+ and xoroshiro that were used in Google Chrome back in 2015. It is notable as one of the few modern PRNGs with a 32-bit version. xoroshiro64** is also a promising option, but only has a 64-bit state and has largely been replaced by xoshiro.

The authors claim it passes randomness tests well (albeit with caveats). Other researchers have pointed out that fails some tests in BigCrush (particularly LinearComp and BinaryRank). But it should not matter in practice, especially if the 32-bit value is converted to a float between 0-1 like these PRNGs are. However, it may cause an issue if you rely on the low-order bits.

JSF (Jenkins' Small Fast)

This is JSF or 'smallprng' by Bob Jenkins (2007), the guy who made ISAAC and SpookyHash. It performs well on PractRand tests and should be quite fast. The average period length is assumed to be 2^126 but 'hasn't been formally determined'.

function jsf32(a, b, c, d) {
    return function() {
        a |= 0; b |= 0; c |= 0; d |= 0;
        var t = a - (b << 27 | b >>> 5) | 0;
        a = b ^ (c << 17 | c >>> 15);
        b = c + d | 0;
        c = d + t | 0;
        d = a + t | 0;
        return (d >>> 0) / 4294967296;
    }
}

While not entirely necessary, the author of JSF suggests seeding it this way, as its period length guarantees are based on the following construction:

var seed = 1337; // any 32-bit integer;
var rand = jsf32(0xF1EA5EED, seed, seed, seed);
for(var i = 0; i < 20; i++) rand(); // advance 20 times

LCG (aka Lehmer/Park-Miller RNG or MCG)

This one is only here to provide a better alternative to options mentioned in other answers such as the Math.sin or Math.PI methods, which are less consistent or reliable across platforms. This LCG implementation is extremely fast but only has a 31-bit state and fails some statistical tests that previously mentioned generators pass with flying colors. It's a one-liner though—which is nice :).

var LCG=s=>()=>(2**31-1&(s=Math.imul(48271,s)))/2**31;

This is called the minimal standard RNG as proposed by Park–Miller in 1988 & 1993 and implemented in C++11 as minstd_rand. Keep in mind that the state and period are only 31-bit (31 bits give 2 billion possible states, 32 bits give double that). This is the very type of PRNG that others are trying to replace.

It'll work, but I wouldn't use it unless you really need speed and don't care about randomness quality (what is random anyway?) or if you don't mind the 31-bit state/period size. Great for a game jam or a demo or something. LCGs suffer from seed correlations, so it is best to discard the first result of an LCG.

There seems to be other multipliers that do offer a full 32-bit state. I have no clue if these are any better/worse statistically than the Park-Miller one, but here they are for completeness.

var LCG=s=>()=>(s=Math.imul(741103597,s)>>>0)/2**32;
var LCG=s=>()=>(s=Math.imul(1597334677,s)>>>0)/2**32;

These LCG values are from: P. L'Ecuyer: A table of Linear Congruential Generators of different sizes and good lattice structure, April 30 1997.


No, but here's a simple pseudorandom generator, an implementation of Multiply-with-carry I adapted from Wikipedia (has been removed since):

var m_w = 123456789;
var m_z = 987654321;
var mask = 0xffffffff;

// Takes any integer
function seed(i) {
    m_w = (123456789 + i) & mask;
    m_z = (987654321 - i) & mask;
}

// Returns number between 0 (inclusive) and 1.0 (exclusive),
// just like Math.random().
function random()
{
    m_z = (36969 * (m_z & 65535) + (m_z >> 16)) & mask;
    m_w = (18000 * (m_w & 65535) + (m_w >> 16)) & mask;
    var result = ((m_z << 16) + (m_w & 65535)) >>> 0;
    result /= 4294967296;
    return result;
}

EDIT: fixed seed function by making it reset m_z
EDIT2: Serious implementation flaws have been fixed


Antti Sykäri's algorithm is nice and short. I initially made a variation that replaced Javascript's Math.random when you call Math.seed(s), but then Jason commented that returning the function would be better:

Math.seed = function(s) {
    return function() {
        s = Math.sin(s) * 10000; return s - Math.floor(s);
    };
};

// usage:
var random1 = Math.seed(42);
var random2 = Math.seed(random1());
Math.random = Math.seed(random2());

This gives you another functionality that Javascript doesn't have: multiple independent random generators. That is especially important if you want to have multiple repeatable simulations running at the same time.


Please see Pierre L'Ecuyer's work going back to the late 1980s and early 1990s. There are others as well. Creating a (pseudo) random number generator on your own, if you are not an expert, is pretty dangerous, because there is a high likelihood of either the results not being statistically random or in having a small period. Pierre (and others) have put together some good (pseudo) random number generators that are easy to implement. I use one of his LFSR generators.

https://www.iro.umontreal.ca/~lecuyer/myftp/papers/handstat.pdf

Phil Troy


Combining some of the previous answers, this is the seedable random function you are looking for:

Math.seed = function(s) {
    var mask = 0xffffffff;
    var m_w  = (123456789 + s) & mask;
    var m_z  = (987654321 - s) & mask;

    return function() {
      m_z = (36969 * (m_z & 65535) + (m_z >>> 16)) & mask;
      m_w = (18000 * (m_w & 65535) + (m_w >>> 16)) & mask;

      var result = ((m_z << 16) + (m_w & 65535)) >>> 0;
      result /= 4294967296;
      return result;
    }
}

var myRandomFunction = Math.seed(1234);
var randomNumber = myRandomFunction();

To write your own pseudo random generator is quite simple.

The suggestion of Dave Scotese is useful but, as pointed out by others, it is not quite uniformly distributed.

However, it is not because of the integer arguments of sin. It's simply because of the range of sin, which happens to be a one dimensional projection of a circle. If you would take the angle of the circle instead it would be uniform.

So instead of sin(x) use arg(exp(i * x)) / (2 * PI).

If you don't like the linear order, mix it a bit up with xor. The actual factor doesn't matter that much either.

To generate n pseudo random numbers one could use the code:

function psora(k, n) {
  var r = Math.PI * (k ^ n)
  return r - Math.floor(r)
}
n = 42; for(k = 0; k < n; k++) console.log(psora(k, n))

Please also note that you cannot use pseudo random sequences when real entropy is needed.


Many people who need a seedable random-number generator in Javascript these days are using David Bau's seedrandom module.


Math.random no, but the ran library solves this. It has almost all distributions you can imagine and supports seeded random number generation. Example:

ran.core.seed(0)
myDist = new ran.Dist.Uniform(0, 1)
samples = myDist.sample(1000)

I have written a function that returns a seeded random number, it uses Math.sin to have a long random number and uses the seed to pick numbers from that.

Use :

seedRandom("k9]:[email protected]", 15)

it will return your seeded number the first parameter is any string value ; your seed. the second parameter is how many digits will return.

     function seedRandom(inputSeed, lengthOfNumber){

           var output = "";
           var seed = inputSeed.toString();
           var newSeed = 0;
           var characterArray = ['0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','y','x','z','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','U','R','S','T','U','V','W','X','Y','Z','!','@','#','$','%','^','&','*','(',')',' ','[','{',']','}','|',';',':',"'",',','<','.','>','/','?','`','~','-','_','=','+'];
           var longNum = "";
           var counter = 0;
           var accumulator = 0;

           for(var i = 0; i < seed.length; i++){
                var a = seed.length - (i+1);
                for(var x = 0; x < characterArray.length; x++){
                     var tempX = x.toString();
                     var lastDigit = tempX.charAt(tempX.length-1);
                     var xOutput = parseInt(lastDigit);
                     addToSeed(characterArray[x], xOutput, a, i); 
                }                  
           }

                function addToSeed(character, value, a, i){
                     if(seed.charAt(i) === character){newSeed = newSeed + value * Math.pow(10, a)}
                }
                newSeed = newSeed.toString();

                var copy = newSeed;
           for(var i=0; i<lengthOfNumber*9; i++){
                newSeed = newSeed + copy;
                var x = Math.sin(20982+(i)) * 10000;
                var y = Math.floor((x - Math.floor(x))*10);
                longNum = longNum + y.toString()
           }

           for(var i=0; i<lengthOfNumber; i++){
                output = output + longNum.charAt(accumulator);
                counter++;
                accumulator = accumulator + parseInt(newSeed.charAt(counter));
           }
           return(output)
      }

A simple approach for a fixed seed:

function fixedrandom(p){
    const seed = 43758.5453123;
    return (Math.abs(Math.sin(p)) * seed)%1;
}

For a number between 0 and 100.

Number.parseInt(Math.floor(Math.random() * 100))