A-Shell supports two pseudorandom number generation algorithms, exposed via the following three functions:
RND(seedop)
RND2()
SRND2(seed {,ubound, lbound {,stream}})
RND(seedop) has been included in A-Shell since version 1.0, and is semantically compatible with the AMOS function of the same name. That is to say, it is source and run time compatible, but doesn't generate the same sequence of output values as the AMOS version. Based on the standard C library functions rand() and srand(), which are in turn based on different underlying algorithms on different operating system platforms, its output varies across platforms and possibly even versions of the same platform. Depending on the seedop parameter, RND(seedop) either initializes the generator or returns the next value. The values returned are always in the range of 0 to 1.
RND2() was introduced in A-Shell version 6.3.1517, and is not in any way compatible with the AMOS version. However, because it is implemented directly within A-Shell, it is guaranteed to be stable and compatible across all A-Shell platforms and versions going forward, which is important for certain encryption and testing applications. It is also offers some other advantages, described below. RND2() takes no parameters; it only returns the next value, based on the initialization/state. The values returned may be fractional in the range of 0 to 1, or they may be integers in an arbitrarily specified range, depending on the initialization parameters.
SRND2(seed {,ubound, lbound {,stream}}) initializes the RND2() generator.
Parameters
seedop (32 bit integer value)
If >= 0, causes the function to return the next value in the sequence. If < 0, acts as the seed to initialize the RND() generator. You can also establish a randomly selected seed by executing the RANDOMIZE statement.
seed (32 bit integer value)
establishes the initial state of the RND2() generator. A seed value of 0, combined with a stream value of -1, results in a randomly selected seed—equivalent to executing the RANDOMIZE statement.
ubound, lbound (32 bit signed integer value)
optionally determine the range of returned values. If omitted or equal to each other, the range of returned values will be from 0 to 1 (fractional) as with the traditional RND(x). Otherwise, the returned values will be integers, uniformly distributed across the range specified by lbound and ubound, inclusive.
stream (32 bit signed integer value)
optionally selects one of 2^32 “streams” or sequences within a given seed. Combining 2^32 streams with 2^32 seeds increases the universe of possible sets/sequences of random values dramatically. Note that for a given seed, different streams are guaranteed never to overlap each other. The default stream is 0, which, unlike the case with seed, does not result in a randomly selected stream. A stream value of -1 is used in conjunction with seed = 0 to set a random seed.
Comments
Even though SRND2() doesn't return any value, because it is a function, it needs to be used in an expression, typically a dummy assignment statement, e.g.
x = SRND2(seed,ubound,lbound) ! use a dummy assignment to invoke SRND2()
If RND2() is called without first initializing the generator with SRND2(seed,...), it will be automatically initialized as if SRND2(0,0,1,-1) had been called, i.e. a random seed will be selected and the range of returned values will be from 0 to 1 (fractional). Note that random seed initialization is relative to the A-Shell session, not just to the current program; so a program that fails to initialize the generator is somewhat at the mercy of whatever state previous programs left the generator in.
The RANDOMIZE statement initializes both generators to a non-deterministically selected psuedorandom seed and, in the case of RND2(), stream. It does not affect previously established lbound and ubound values.
Aside from stability and uniformity, the RND2() 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 might otherwise result in a fractional value very close to 1 acting as equivalent to 1 in an expression, which in turn could cause program logic intending to generate values in a range of 1 to N—e.g. INT(RND(1)*N)+1—to generate a value N+1, leading to application errors. |
• | RND2() is much less predictable than RND(), making it superior for cryptographic uses. |
• | RND2() has a wider, more granular range of output values, especially compared to the Windows implementation of RND(seedop) which is limited to 16 bits. |
• | Splitting it into two functions, one to initialize and one to generate, reduces the confusion inherent in the multiple operations of RND(seedop). |
RND2() is based on 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.
History
2016 July, A-Shell 6.3.1517: RND2() and SRND2(seed,…) functions added to A-Shell.