Is it possible to seed the random number generator (Math.random) in Javascript?
问题:
回答1:
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.
回答2:
My other answer represents a more traditional algorithm, but I found Dave Scotese's comment to this answer to be a more eloquent one. Unfortunately, it's pretty slow due to string manipulation.
Here's a version that is about 20 times faster and a bit more precise as well.
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.
回答3:
No, but here's a simple pseudorandom generator I adapted from Wikipedia:
var m_w = 123456789; var m_z = 987654321; var mask = 0xffffffff; // Takes any integer function seed(i) { m_w = i; m_z = 987654321; } // 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
EDIT: fixed seed function by making it reset m_z
回答4:
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.
回答5:
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
回答6:
Combining some of the previous answers, this is the seedable random function you are looking for:
Math.seed = function(s) { var m_w = s; var m_z = 987654321; var mask = 0xffffffff; 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
Be careful using this one though, I don't believe the distribution of random numbers is very good, it seems to weight towards the 0 to .5 range. At least that was my experience in the random walk visualization I was making.
回答7:
I recommend Alea for fast, high quality randomness (desinged for JS, passes BigCrush test suite):
function Alea(seed) { if(seed === undefined) {seed = +new Date() + Math.random();} function Mash() { var n = 4022871197; return function(r) { for(var t, s, u = 0, e = 0.02519603282416938; u
If you only need a basic PRNG, the Lehmer LCG is much better than the Math.sin
method in other answers here:
function LCG(seed) { function lcg(a) {return a * 48271 % 2147483647} seed = seed ? lcg(seed) : lcg(Math.random()); return function() {return (seed = lcg(seed)) / 2147483648} }
To use them, you call the main function to init the PRNG with a seed, then call its returned function to generate subsequent numbers:
var rand = Alea("123"); rand(); // 0.4801303152926266
or
var rand = LCG(123); rand(); // 0.45899124443531036
回答8:
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
Please also note that you cannot use pseudo random sequences when real entropy is needed.
回答9:
Many people who need a seedable random-number generator in Javascript these days are using David Bau's seedrandom module.