Can't generate random number within whole span of non-negative integers

I ran into an issue today on 6M62 trying to generate a random number across the legal range of non-negative integers. The phrase

a random number between 0 and max

where max is defined as the maximum positive integer was not working as expected.

The 6M62 template code for random number generation is:

[ GenerateRandomNumber n m s;
    if (n==m) return n;
    if (n>m) { s = n; n = m; m = s; }
    n--;
    return random(m-n) + n;
];

The second-to-last line decrements the lower bound number, in this case modifying 0 to -1. The parameter fed to random() is the higher bound minus this adjusted number, in this case (compiling to Z-Machine) translating to 32767-(-1) == 32768. This pushes the value into negative number territory when interpreted as signed, which is making the I6 level treat the call to random() as a command to set a seed value for the RNG.

It looks as though any suitably large difference between the upper and lower bounds will cause the same sort of problem. Maybe it would be worthwhile to generate an RTE in this case? (Maybe v10.1 already does, for that matter.)

2 Likes

The generated I6 remains the same in v10. Yeah, ideally this’d generate a run-time error. Something like this’d do it, I think.

Include (-
[ GenerateRandomNumber n m s;
    if (n==m) return n;
    if (n>m) { s = n; n = m; m = s; }
    n--;
    s = m - n;
    if (s < 1) {
      print "** random range out of range^";
      return 1;
    }
    return random(s) + n;
];
-) replacing "GenerateRandomNumber".

Seems a shame, though, to limit Glulx to half the range when it doesn’t have to be.


Include (-
[ GenerateRandomNumber n m s;
    if (n==m) return n;
    if (n>m) { s = n; n = m; m = s; }
    n--;
    s = m - n;
#ifdef TARGET_ZCODE;
    if (s < 1) {
      print "** random range out of range^";
      return 1;
    }
    return random(s) + n;
#endif;
#ifdef TARGET_GLULX;
    if (s > 0) return random(s) + n;
    n++;
    while (true) {
      @random 0 s;
      if ((s >= n) && (s <= m)) {
         return s;
       }
    }
#endif;
];
-) replacing "GenerateRandomNumber".

Better.

Include (-
[ GenerateRandomNumber n m s x;
    if (n==m) return n;
    if (n>m) {  s = n; n = m; m = s; }
    x = 1 + m - n;
    if (x > 0) return random(x) + n - 1;
#ifdef TARGET_ZCODE;
   print "** random range out of range^";
   return 1;
#endif;
#ifdef TARGET_GLULX;
    while (true) {
      @random 0 x;
      if ((x >= n) && (x <= m)) return x;
    }
#endif;
];
-) replacing "GenerateRandomNumber".

Edited to fix a bug Otis caught.

1 Like