Reputation: 532
I recently figured out how to get a random number via google, and it got me thinking how does Math.random()
work. So here I am I can not figure out how they did Math.random() unless they used a time like thing does anyone know how JavaScript's Math.random()
works or an equivalent?
Upvotes: 33
Views: 33754
Reputation: 319
you may want this article for a reference: https://hackernoon.com/how-does-javascripts-math-random-generate-random-numbers-ef0de6a20131
And btw, recently I am also curious about this question and then read the source code of NodeJS. We can know one possible implementation from Google V8:
The main entry for the random (MathRandom::RefillCache
function):
https://github.com/v8/v8/blob/master/src/numbers/math-random.cc
How the seed initialized? see also here: https://github.com/v8/v8/blob/master/src/base/utils/random-number-generator.cc#L31
The key function is (XorShift128
function):
https://github.com/v8/v8/blob/master/src/base/utils/random-number-generator.h#L119
in this header file, there are references to some papers:
// See Marsaglia: http://www.jstatsoft.org/v08/i14/paper
// And Vigna: http://vigna.di.unimi.it/ftp/papers/xorshiftplus.pdf
Upvotes: 1
Reputation: 4112
Math.random() returns a Number value with a positive sign, greater than or equal to 0 but less than 1, chosen randomly or pseudo randomly with approximately uniform distribution over that range, using an implementation-dependent algorithm or strategy.
Here's V8's implementation:
uint32_t V8::Random() {
// Random number generator using George Marsaglia's MWC algorithm.
static uint32_t hi = 0;
static uint32_t lo = 0;
// Initialize seed using the system random(). If one of the seeds
// should ever become zero again, or if random() returns zero, we
// avoid getting stuck with zero bits in hi or lo by reinitializing
// them on demand.
if (hi == 0) hi = random();
if (lo == 0) lo = random();
// Mix the bits.
hi = 36969 * (hi & 0xFFFF) + (hi >> 16);
lo = 18273 * (lo & 0xFFFF) + (lo >> 16);
return (hi << 16) + (lo & 0xFFFF);
}
Here are a couple of related threads on StackOverflow:
Upvotes: 34
Reputation: 25449
See: There's Math.random(), and then there's Math.random()
Until recently (up to version 4.9.40), V8’s choice of PRNG was MWC1616 (multiply with carry, combining two 16-bit parts). It uses 64 bits of internal state and looks roughly like this:
uint32_t state0 = 1;
uint32_t state1 = 2;
uint32_t mwc1616() {
state0 = 18030 * (state0 & 0xffff) + (state0 >> 16);
state1 = 30903 * (state1 & 0xffff) + (state1 >> 16);
return state0 << 16 + (state1 & 0xffff);
The 32-bit value is then turned into a floating point number between 0 and 1 in agreement with the specification.
MWC1616 uses little memory and is pretty fast to compute, but unfortunately offers sub-par quality:
This has been pointed out to us, and having understood the problem and after some research, we decided to reimplement Math.random based on an algorithm called xorshift128+. It uses 128 bits of internal state, has a period length of 2^128 - 1, and passes all tests from the TestU01 suite.
uint64_t state0 = 1;
uint64_t state1 = 2;
uint64_t xorshift128plus() {
uint64_t s1 = state0;
uint64_t s0 = state1;
state0 = s0;
s1 ^= s1 << 23;
s1 ^= s1 >> 17;
s1 ^= s0;
s1 ^= s0 >> 26;
state1 = s1;
return state0 + state1;
}
The new implementation landed in V8 4.9.41.0 within a few days of us becoming aware of the issue. It will become available with Chrome 49. Both Firefox and Safari switched to xorshift128+ as well.
Upvotes: 14
Reputation: 13
<script>
function generateRandom(){ // Generate and return a random number
var num = Math.random();
num = (Math.round((num*10)))%10;
return num;
}
function generateSum(){ // Generate a problem
document.getElementById("ans").focus();
var num1 = generateRandom();
var num2 = generateRandom();
document.getElementById("num1").innerHTML = num1;
document.getElementById("num2").innerHTML = num2;
document.getElementById("pattern1").innerHTML = printPattern(num1);
document.getElementById("pattern2").innerHTML = printPattern(num2);
}
function printPattern(num){ // Generate the star pattern with 'num' number of stars
var pattern = "";
for(i=0; i<num; i++){
if((i+1)%4 == 0){
pattern = pattern+"*<br>";
}
else{
pattern = pattern+"*";
}
}
return pattern;
}
function checkAns(){ // Check the answer and give the response
var num1 = parseInt(document.getElementById("num1").innerHTML);
var num2 = parseInt(document.getElementById("num2").innerHTML);
var enteredAns = parseInt(document.getElementById("ans").value);
if ((num1+num2) == enteredAns){
document.getElementById("patternans").innerHTML = printPattern(enteredAns);
document.getElementById("patternans").innerHTML += "<br>Correct";
}
else{
document.getElementById("patternans").innerHTML += "Wrong";
//remove + mark to remove the error
}
}
function newSum(){
generateSum();
document.getElementById("patternans").innerHTML = "";
document.getElementById("ans").value = "";
}
</script>
Upvotes: -4
Reputation: 700910
It's correct that they use a "time like thing". A pseudo random generator is typically seeded using the system clock, because that is a good source of a number that isn't always the same.
Once the random generator is seeded with a number, it will generate a series of numbers that all depending on the initial value, but in such a way that they seem random.
A simple random generator (that was actually used in programming languages a while back) is to use a prime number in an algorithm like this:
rnd = (rnd * 7919 + 1) & 0xffff;
This will produce a series of numbers that jump back and forth, seemingly random. For example:
seed = 1337
36408
22089
7208
63833
14360
11881
41480
13689
6648
The random generator in Javascript is just a bit more complex (to give even better distribution) and uses larger numbers (as it has to produce a number that is about 60 bits instead of 16), but it follows the same basic principle.
Upvotes: 6