davidbau / seedrandom

seeded random number generator for Javascript
2.04k stars 160 forks source link

Math.random() rounds down when values are close to 0 #83

Open hellopir2 opened 3 weeks ago

hellopir2 commented 3 weeks ago

I don't know if this is ever possible to reproduce with any (known) seed, but if the next 120 arc4 outputs are 0, followed by a value less than 16, d will overflow to Infinity, making all outputs regardless of value 0. This means that contrary to what the comment // randomness in every bit of the mantissa of the IEEE 754 value. says, it doesn't actually produce any values between 0 and 2^-964.

This can be fixed by changing d to the log_0.5 of the actual denominator and forcing d <= 1074. If this is going to be fixed, a better solution would be to just change the hardcoded constants and add new ones, but here is a quick fix I made.

  var prng = function() {
    var n = arc4.g(chunks),                 // Start with a numerator n < 2 ^ 48
        d = Math.log2(startdenom),          //   and denominator d = 48.
        x = 0;                              //   and no 'extra last byte'.
    while (n < significance && d < 1074) {  // Fill up all significant digits by
      n = (n + x) * width;                  //   shifting numerator and
      d += Math.log2(width);                //   denominator and generating a
      x = arc4.g(1);                        //   new least-significant-byte.
    }
    while (n >= overflow || d > 1074) {     // To avoid rounding up, before adding
      n /= 2;                               //   last byte, shift everything
      d -= 1;                               //   right using integer math until
      x >>>= 1;                             //   we have exactly the desired bits.
    }
    return (n + x) * Math.pow(2, -d);       // Form the number within [0, 1).
  };

This is not an issue anyone will ever encounter, but I just noticed this and wanted to comment on it :).