SRAND2 and RND2

New random number generator implemented and exposed through two new functions:

SRND2(seed {,ubound, lbound {,stream}})

RND2(x)

SRND2 initializes the generator, RND2 returns the next random number per the initialization/state.

Parameters

seed  (32 bit integer)

establishes the initial state of the generator. The sequence of numbers returned from RND2() will be different for each seed. A seed value of 0 results in a randomly selected seed, which is equivalent to executing the RANDOMIZE statement.

ubound, lbound  (32 bit signed integer)

may be used to optionally set the range of returned values. If omitted or set equal to each other, the range of returned values will be from 0 to 1 (fractional) as with the traditional RND(). Otherwise, the returned values will be integers, uniformly distributed across the range specified by lbound and ubound, inclusive.

stream  (32 bit integer)

may optionally be specified to select one of the multiple streams of values possible for a given seed. Combining 2^32 streams with 2^32 seeds increases the universe of possible sets/sequences of random values dramatically, but for most uses is probably not of much interest. Note however, that for a given seed, different streams are guaranteed never to overlap each other.

If RND2() is called without first initializing the generator with SRND2(), it will be automatically initialized as if SRND2(0) had been called, i.e. a random seed will be selected and the range of returned values will be from 0 to 1 (fractional).

The existing RANDOMIZE statement affects the new RND2() function in the same way as the traditional RND(x) function, i.e. establishes a pseudo-random seed and stream. It does not affect previously established lbound and ubound values.

The primary motivation for implementing a new random number generator is to provide vertical stability across versions and horizontal uniformity across platforms. That is, for a given set of initialization parameters, the resulting sequence of numbers returned by the new RND2() function will be the same across all A-Shell platforms, all versions going forward, and all operating system levels. This is NOT the case with the traditional RND() function, which is based on standard C library routines which have different underlying implementations in different operating systems and which may change over time. Stability and uniformity are critical for many applications of random number generators, including data encryption and test suites.

Aside from stability and uniformity, the new generator offers some additional benefits:

•   The lbound,ubound feature makes it much easier and faster to generate integers in a particular range, which is probably the most common usage. It also eliminates the floating point rounding problem which allows the traditional RND(x) to sometimes return a value effectively equivalent to 1. If you are converting the result to an integer range 1-N in the usual way, i.e. INT(RND(1)*N)+1, this would lead to a result of N+1, possibly causing an error in the application.

•   RND2() is much less predictable than RND(), making it superior for cryptographic uses.

•   Splitting it into two functions, one to initialize and one to generate, reduces the confusion inherent in the overloaded nature of RND(x).

The new generator is based on the the PCG family of random number generators; see www.pcg-random.org for more information.

Warning: attempting to run a program containing RND2() or SRND2() in a version of A-Shell prior to 6.3.1517 will generate an unsupported function error when it hits either function.