davidbau / seedrandom

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

arc4.g in prng function sometimes returns NaN #74

Open kgh-85 opened 3 years ago

kgh-85 commented 3 years ago

arc4.g in prng function sometimes (rare) returns NaN. Software used: Scripting interface of Adobe After Effects 2020

For folks having the same issue: I did this (ugly) quickfix which works:

  // This function returns a random double in [0, 1) that contains
  // randomness in every bit of the mantissa of the IEEE 754 value.
  var prng = function() {
    var n = arc4.g(chunks);             // Start with a numerator n < 2 ^ 48
    while (isNaN(n)) {                  //   [KGH] Quickfix
      n = arc4.g(chunks);               //   [KGH] Quickfix
    }                                   //   [KGH] Quickfix
    var d = startdenom,                 //   and denominator d = 2 ^ 48.
        x = 0;                          //   and no 'extra last byte'.
    while (n < significance) {          //   Fill up all significant digits by
      n = (n + x) * width;              //   shifting numerator and
      d *= width;                       //   denominator and generating a
      x = arc4.g(1);                    //   new least-significant-byte.
      while (isNaN(x)) {                //   [KGH] Quickfix
        x = arc4.g(1);                  //   [KGH] Quickfix
      }                                 //   [KGH] Quickfix
    }
    while (n >= overflow) {             // To avoid rounding up, before adding
      n /= 2;                           //   last byte, shift everything
      d /= 2;                           //   right using integer math until
      x >>>= 1;                         //   we have exactly the desired bits.
    }
    return (n + x) / d;                 // Form the number within [0, 1).
  };
davidbau commented 3 years ago

Fascinating. I have not seen this in any of the browsers AFAIK. Some questions, if you know or if you have have time. (1) Have you seen this on any browsers? (2) Do you know what JS engine is used in After Effects? (3) Can you measure how frequently NaN is returned?

On Sun, Nov 8, 2020 at 5:30 PM Konrad Hinkelmann notifications@github.com wrote:

arc4.g in prng function sometimes (rare) returns NaN. Software used: Scripting interface of Adobe After Effects 2020

For folks having the same issue: I did this (ugly) quickfix which works:

// This function returns a random double in [0, 1) that contains // randomness in every bit of the mantissa of the IEEE 754 value. var prng = function() { var n = arc4.g(chunks); // Start with a numerator n < 2 ^ 48 while (isNaN(n)) { // [KGH] Quickfix n = arc4.g(chunks); // [KGH] Quickfix } // [KGH] Quickfix var d = startdenom, // and denominator d = 2 ^ 48. x = 0; // and no 'extra last byte'. while (n < significance) { // Fill up all significant digits by n = (n + x) width; // shifting numerator and d = width; // denominator and generating a x = arc4.g(1); // new least-significant-byte. while (isNaN(x)) { // [KGH] Quickfix x = arc4.g(1); // [KGH] Quickfix } // [KGH] Quickfix } while (n >= overflow) { // To avoid rounding up, before adding n /= 2; // last byte, shift everything d /= 2; // right using integer math until x >>>= 1; // we have exactly the desired bits. } return (n + x) / d; // Form the number within [0, 1). };

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/davidbau/seedrandom/issues/74, or unsubscribe https://github.com/notifications/unsubscribe-auth/AA2MN2D7PJ4ENXLG5IQXR53SO4LYVANCNFSM4TOTNE6A .

kgh-85 commented 3 years ago

Hey.

(1) No, not tested (2) This site says "Is based on ECMAScript 3 (1999)" (3) Currently no time to test. Maybe later.

matthewoates commented 2 years ago

This is a terrifying bug. Were you able to reproduce this with any kind of seed @kgh-85?

I'm stress testing this at the moment with the following code which would allow us to reproduce any issue found:

const seedrandom = require('seedrandom');

for (let i = 0; i < 1e8; i++) {
  const seed = String(Math.random());
  const rng = seedrandom(seed);
  console.log('trying with seed:', seed);

  for (let i = 0; i < 1e8; i++) {
    if (isNaN(rng.int32())) {
      throw new Error('int32 NaN');
    }

    if (isNaN(rng.quick())) {
      throw new Error('quick NaN');
    }

    if (isNaN(rng())) {
      throw new Error('() NaN');
    }
  }
}

I'll report back with findings.

kgh-85 commented 2 years ago

Hey Matt, unfortunately not.

It was sporadic and as you can see in my quickfix I just recall the same function with the same values so I don't think it is related to the seed itself.

You should be able to reproduce it quite fast with the scripting interface of adobe after effects.

Bests Konrad

matthewoates commented 2 years ago

@kgh-85 thanks for the response. The purpose of using a seed is to be able to reproduce the issue later. Using a seed shouldn't prevent this issue from happening if this issue exists. The only thing I can think of is that this is an environment issue.

After 700,000,000,000 iterations with no NaN results using node v16.13.1 I can say that this bug doesn't exist with my environment or is astronomically improbable. cc @davidbau

davidbau commented 2 years ago

Thanks for testing this Matt!

I suspect there is some flaw in Adobe After Effects javascript implementation, but I'm not sure anybody with access to that environment has tried it since @kgh-85's original report.