Seedable JavaScript random number generator

前端 未结 9 707
暖寄归人
暖寄归人 2020-11-22 10:13

The JavaScript Math.random() function returns a random value between 0 and 1, automatically seeded based on the current time (similar to Java I believe). However, I don\'t

相关标签:
9条回答
  • 2020-11-22 10:41

    Note: This code was originally included in the question above. In the interests of keeping the question short and focused, I've moved it to this Community Wiki answer.

    I found this code kicking around and it appears to work fine for getting a random number and then using the seed afterward but I'm not quite sure how the logic works (e.g. where the 2345678901, 48271 & 2147483647 numbers came from).

    function nextRandomNumber(){
      var hi = this.seed / this.Q;
      var lo = this.seed % this.Q;
      var test = this.A * lo - this.R * hi;
      if(test > 0){
        this.seed = test;
      } else {
        this.seed = test + this.M;
      }
      return (this.seed * this.oneOverM);
    }
    
    function RandomNumberGenerator(){
      var d = new Date();
      this.seed = 2345678901 + (d.getSeconds() * 0xFFFFFF) + (d.getMinutes() * 0xFFFF);
      this.A = 48271;
      this.M = 2147483647;
      this.Q = this.M / this.A;
      this.R = this.M % this.A;
      this.oneOverM = 1.0 / this.M;
      this.next = nextRandomNumber;
      return this;
    }
    
    function createRandomNumber(Min, Max){
      var rand = new RandomNumberGenerator();
      return Math.round((Max-Min) * rand.next() + Min);
    }
    
    //Thus I can now do:
    var letters = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'];
    var numbers = ['1','2','3','4','5','6','7','8','9','10'];
    var colors = ['red','orange','yellow','green','blue','indigo','violet'];
    var first = letters[createRandomNumber(0, letters.length)];
    var second = numbers[createRandomNumber(0, numbers.length)];
    var third = colors[createRandomNumber(0, colors.length)];
    
    alert("Today's show was brought to you by the letter: " + first + ", the number " + second + ", and the color " + third + "!");
    
    /*
      If I could pass my own seed into the createRandomNumber(min, max, seed);
      function then I could reproduce a random output later if desired.
    */
    
    0 讨论(0)
  • 2020-11-22 10:41

    OK, here's the solution I settled on.

    First you create a seed value using the "newseed()" function. Then you pass the seed value to the "srandom()" function. Lastly, the "srandom()" function returns a pseudo random value between 0 and 1.

    The crucial bit is that the seed value is stored inside an array. If it were simply an integer or float, the value would get overwritten each time the function were called, since the values of integers, floats, strings and so forth are stored directly in the stack versus just the pointers as in the case of arrays and other objects. Thus, it's possible for the value of the seed to remain persistent.

    Finally, it is possible to define the "srandom()" function such that it is a method of the "Math" object, but I'll leave that up to you to figure out. ;)

    Good luck!

    JavaScript:

    // Global variables used for the seeded random functions, below.
    var seedobja = 1103515245
    var seedobjc = 12345
    var seedobjm = 4294967295 //0x100000000
    
    // Creates a new seed for seeded functions such as srandom().
    function newseed(seednum)
    {
        return [seednum]
    }
    
    // Works like Math.random(), except you provide your own seed as the first argument.
    function srandom(seedobj)
    {
        seedobj[0] = (seedobj[0] * seedobja + seedobjc) % seedobjm
        return seedobj[0] / (seedobjm - 1)
    }
    
    // Store some test values in variables.
    var my_seed_value = newseed(230951)
    var my_random_value_1 = srandom(my_seed_value)
    var my_random_value_2 = srandom(my_seed_value)
    var my_random_value_3 = srandom(my_seed_value)
    
    // Print the values to console. Replace "WScript.Echo()" with "alert()" if inside a Web browser.
    WScript.Echo(my_random_value_1)
    WScript.Echo(my_random_value_2)
    WScript.Echo(my_random_value_3)
    

    Lua 4 (my personal target environment):

    -- Global variables used for the seeded random functions, below.
    seedobja = 1103515.245
    seedobjc = 12345
    seedobjm = 4294967.295 --0x100000000
    
    -- Creates a new seed for seeded functions such as srandom().
    function newseed(seednum)
        return {seednum}
    end
    
    -- Works like random(), except you provide your own seed as the first argument.
    function srandom(seedobj)
        seedobj[1] = mod(seedobj[1] * seedobja + seedobjc, seedobjm)
        return seedobj[1] / (seedobjm - 1)
    end
    
    -- Store some test values in variables.
    my_seed_value = newseed(230951)
    my_random_value_1 = srandom(my_seed_value)
    my_random_value_2 = srandom(my_seed_value)
    my_random_value_3 = srandom(my_seed_value)
    
    -- Print the values to console.
    print(my_random_value_1)
    print(my_random_value_2)
    print(my_random_value_3)
    
    0 讨论(0)
  • 2020-11-22 10:42

    The code you listed kind of looks like a Lehmer RNG. If this is the case, then 2147483647 is the largest 32-bit signed integer, 2147483647 is the largest 32-bit prime, and 48271 is a full-period multiplier that is used to generate the numbers.

    If this is true, you could modify RandomNumberGenerator to take in an extra parameter seed, and then set this.seed to seed; but you'd have to be careful to make sure the seed would result in a good distribution of random numbers (Lehmer can be weird like that) -- but most seeds will be fine.

    0 讨论(0)
提交回复
热议问题