Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
A very simple, seedable JavaScript PRNG.
/**
* Creates a pseudo-random value generator. The seed must be an integer.
*
* Uses an optimized version of the Park-Miller PRNG.
* http://www.firstpr.com.au/dsp/rand31/
*/
function Random(seed) {
this._seed = seed % 2147483647;
if (this._seed <= 0) this._seed += 2147483646;
}
/**
* Returns a pseudo-random value between 1 and 2^32 - 2.
*/
Random.prototype.next = function () {
return this._seed = this._seed * 16807 % 2147483647;
};
/**
* Returns a pseudo-random floating point number in range [0, 1).
*/
Random.prototype.nextFloat = function (opt_minOrMax, opt_max) {
// We know that result of next() will be 1 to 2147483646 (inclusive).
return (this.next() - 1) / 2147483646;
};
@madole

This comment has been minimized.

Show comment Hide comment
@madole

madole Jul 30, 2014

You dont check that the seed is a number before performing arithmetic calculations on it. potential NaN returned.

madole commented Jul 30, 2014

You dont check that the seed is a number before performing arithmetic calculations on it. potential NaN returned.

@SpaceUnicorn

This comment has been minimized.

Show comment Hide comment
@SpaceUnicorn

SpaceUnicorn Mar 22, 2017

Didn't think it would be this simple, but I guess it is! I wrote a graphic representation of the distribution here: https://www.khanacademy.org/computer-programming/prng-test/5500564014432256
A couple thousand runs show that it's pretty much uniform. Nice work 👍

Didn't think it would be this simple, but I guess it is! I wrote a graphic representation of the distribution here: https://www.khanacademy.org/computer-programming/prng-test/5500564014432256
A couple thousand runs show that it's pretty much uniform. Nice work 👍

@rayfoss

This comment has been minimized.

Show comment Hide comment
@rayfoss

rayfoss Aug 24, 2017

Unlike the Math.sin versions of this, this will produce the same result on Node, Chrome, Safari and Firefox... meaning I can save the seed and regenerate the same results across environments.

rayfoss commented Aug 24, 2017

Unlike the Math.sin versions of this, this will produce the same result on Node, Chrome, Safari and Firefox... meaning I can save the seed and regenerate the same results across environments.

@momander

This comment has been minimized.

Show comment Hide comment
@momander

momander Aug 28, 2017

Very nice! This is just what I needed for my multi-player game, where some random events need to generated on all clients at the same time. With this generator all clients will get the same "random" values, without having to talk over the network.

Very nice! This is just what I needed for my multi-player game, where some random events need to generated on all clients at the same time. With this generator all clients will get the same "random" values, without having to talk over the network.

@TBubba

This comment has been minimized.

Show comment Hide comment
@TBubba

TBubba Sep 19, 2017

Well done! Also, thanks @rayfoss for pointing out that it works across platforms, because that's exactly what I was looking for! 👍

TBubba commented Sep 19, 2017

Well done! Also, thanks @rayfoss for pointing out that it works across platforms, because that's exactly what I was looking for! 👍

@tommitytom

This comment has been minimized.

Show comment Hide comment
@tommitytom

tommitytom Oct 16, 2017

Do bear in mind that the float version will be affected by floating point rounding errors in different ways on different platforms - so if you want the same numbers on all platforms make sure you stick to using the integer version!

Do bear in mind that the float version will be affected by floating point rounding errors in different ways on different platforms - so if you want the same numbers on all platforms make sure you stick to using the integer version!

@AmaanC

This comment has been minimized.

Show comment Hide comment
@AmaanC

AmaanC Dec 1, 2017

Ended up modifying it a little to return random 32-bit signed ints, so I plotted a histogram and a random bitmap to verify the distribution was decent.

Histogram:
https://codepen.io/AmaanC/full/mqawWb/

Bitmap:
https://jsfiddle.net/amaan/nnhp57n0/

AmaanC commented Dec 1, 2017

Ended up modifying it a little to return random 32-bit signed ints, so I plotted a histogram and a random bitmap to verify the distribution was decent.

Histogram:
https://codepen.io/AmaanC/full/mqawWb/

Bitmap:
https://jsfiddle.net/amaan/nnhp57n0/

@ghost

This comment has been minimized.

Show comment Hide comment
@ghost

ghost Dec 19, 2017

Hehe. Talk about an obscure next() algorithm!

It relies on this._seed * 16807 % 2147483647 never becoming "0". If that happens, then all next() calls after that will return 0.

In other words, 1st part (this._seed * 16807) is never allowed to become 2147483647.

Luckily, the number is well-chosen. Because to get 2147483647 % 2147483647 == 0, the 1st part of the equation would have to become 2147483647. So to find out what that number would have to be, we just check 2147483647 / 16807 = 127773.168739216. So we see that we need a very specific, float number for the next() algorithm to bug out.

Luckily, as long as you seed this class with an integer, then the seed * 16807 will never produce a float and can never bug out.

Fascinating algorithm. Thank you...

PS: Your code has some funny variables: Random.prototype.nextFloat = function (opt_minOrMax, opt_max).

ghost commented Dec 19, 2017

Hehe. Talk about an obscure next() algorithm!

It relies on this._seed * 16807 % 2147483647 never becoming "0". If that happens, then all next() calls after that will return 0.

In other words, 1st part (this._seed * 16807) is never allowed to become 2147483647.

Luckily, the number is well-chosen. Because to get 2147483647 % 2147483647 == 0, the 1st part of the equation would have to become 2147483647. So to find out what that number would have to be, we just check 2147483647 / 16807 = 127773.168739216. So we see that we need a very specific, float number for the next() algorithm to bug out.

Luckily, as long as you seed this class with an integer, then the seed * 16807 will never produce a float and can never bug out.

Fascinating algorithm. Thank you...

PS: Your code has some funny variables: Random.prototype.nextFloat = function (opt_minOrMax, opt_max).

@backspaces

This comment has been minimized.

Show comment Hide comment
@backspaces

backspaces Jan 21, 2018

Way cool, thanks! Doesn't repeat itself for quite a while. The sin prng seems to repeat in the low millions.

This is a simpler version for floats only. It returns the PRNG function:

  function randomSeedParkMiller (seed = 123456) { // doesn't repeat b4 JS dies.
    // https://gist.github.com/blixt/f17b47c62508be59987b
    seed = seed % 2147483647
    return () => {
      seed = seed * 16807 % 2147483647
      return (seed - 1) / 2147483646
    }
  }

Here's the sin version:

  function randomSeedSin (seed = Math.PI / 4) { // ~3.4 million b4 repeat.
    // https://stackoverflow.com/a/19303725/1791917
    return () => {
      const x = Math.sin(seed++) * 10000
      return x - Math.floor(x)
    }
  }

It's written to return the function so that it can be used to replace Math.random:

Math.random = randomSeedParkMiller(seed)

Way cool, thanks! Doesn't repeat itself for quite a while. The sin prng seems to repeat in the low millions.

This is a simpler version for floats only. It returns the PRNG function:

  function randomSeedParkMiller (seed = 123456) { // doesn't repeat b4 JS dies.
    // https://gist.github.com/blixt/f17b47c62508be59987b
    seed = seed % 2147483647
    return () => {
      seed = seed * 16807 % 2147483647
      return (seed - 1) / 2147483646
    }
  }

Here's the sin version:

  function randomSeedSin (seed = Math.PI / 4) { // ~3.4 million b4 repeat.
    // https://stackoverflow.com/a/19303725/1791917
    return () => {
      const x = Math.sin(seed++) * 10000
      return x - Math.floor(x)
    }
  }

It's written to return the function so that it can be used to replace Math.random:

Math.random = randomSeedParkMiller(seed)
@santinod

This comment has been minimized.

Show comment Hide comment
@santinod

santinod Jan 30, 2018

With the current code, initialization fails if seed = -2147483646. My suggestion:

function Random(seed) {
  this._seed = Math.abs(seed % 2147483646) + 1;
}

santinod commented Jan 30, 2018

With the current code, initialization fails if seed = -2147483646. My suggestion:

function Random(seed) {
  this._seed = Math.abs(seed % 2147483646) + 1;
}
@juliango202

This comment has been minimized.

Show comment Hide comment
@juliango202

juliango202 Mar 21, 2018

Thanks! There is a typo in the comment for the next() method, the upper limit is 2^31 - 2.

Thanks! There is a typo in the comment for the next() method, the upper limit is 2^31 - 2.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment