Is it possible to seed the random number generator (Math.random) in Javascript?
相关问题
- Is there a limit to how many levels you can nest i
- How to toggle on Order in ReactJS
- void before promise syntax
- Keeping track of variable instances
- Can php detect if javascript is on or not?
A simple approach for a fixed seed:
Many people who need a seedable random-number generator in Javascript these days are using David Bau's seedrandom module.
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:
I've implemented a number of good, short, fast copy-pastable PRNG functions in plain JavaScript. All of them can be seeded and provide good quality numbers.
First of all, remember to seed your PRNGs properly. Most of the generators below have no built-in seeding procedure, but accept one or more 32-bit values to initialize the state of the PRNG. Rather than seeding with just "1" or "123", which is low-entropy and can cause correlations (which is not good), it is best to initialize PRNGs with well-distributed data.
Thankfully, hash algorithms 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 a simple example based on the FNV1a-Mulvey hash:
This function utilizes Bret Mulvey's modified FNV1a 32-bit hash function. Each subsequent call to the returned function produces a new "random" hash value to be used as a seed in a PRNG.
Here's how you might use it:
This is of course functional JS, but it could be objectified.
Onward to the goods (the generators).
sfc32
This gem comes from the PractRand random number testing suite, of which it passes without issue. PractRand is purportedly even more stringent than TestU01. It's also very fast in JS (xoshiro128** is slightly faster, but worse quality). It's probably my PRNG of choice.
Mulberry32
Mulberry32 is also quite fast and has good quality (author states it passes all of gjrand's tests). 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's 4.3 billion states compared to the 340 undecillion in sfc32/xoshiro128**.
xoshiro128**
As of May 2018,
xoshiro128**
is the new member of the xorshift family. It offers a 128-bit state, and is super fast.This PRNG is the latest by Blackman/Vigna who also did xorshift128+ and xoroshiro used in Google Chrome. It is notable as one of the few modern 32-bit PRNGs. xoroshiro64** is also promising, but only has a 64-bit state and has largely been replaced by xoshiro.
Use like so:
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, if you rely on the low bits in an awkward way, it may cause an issue.
JSF
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.This version does not need a separate seed function. But as a result, only 32-bits can be seeded and this version runs pre-runs jsf() 20 times to disperse the initial state, which may be costly.
Used like so:
If need be, the entire 128-bit state can be initialized directly and the for loop removed. I decided to keep the original construction because the author verified the cycle length of every possible 32-bit seed in the given configuration.
Lehmer LCG
This one is only here to provide a better alternative to options mentioned in other answers such as the
Math.sin
orMath.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 :). This is 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 the 31-bit state/period size. Great for a game jam or a demo or something.
Use like so:
There seems to be other multipliers that get you the full 32-bit state. I have no clue if these are any better/worse than the Park-Miller one, but here they are for completeness.
These multipliers are from: P. L'Ecuyer: A table of Linear Congruential Generators of different sizes and good lattice structure, April 30 1997.
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:
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.