How does Math.random() work in javascript?

后端 未结 5 1468
谎友^
谎友^ 2020-11-30 08:23

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

5条回答
  •  挽巷
    挽巷 (楼主)
    2020-11-30 09:15

    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:

    • The number of random values it can generate is limited to 232 as opposed to the 252 numbers between 0 and 1 that double precision floating point can represent.
    • The more significant upper half of the result is almost entirely dependent on the value of state0. The period length would be at most 232, but instead of few large permutation cycles, there are many short ones. With a badly chosen initial state, the cycle length could be less than 40 million.
    • It fails many statistical tests in the TestU01 suite.

    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.

提交回复
热议问题