Troubleshooting
Problem
The API CEERAN0 can be used to generate random numbers using the Qc3GenPRNs API.
Resolving The Problem
On IBM® iSeries™ family of servers, the API CEERAN0 is used to generate random numbers in the (0,1) range; however, in several tests CEERAN0 showed a relatively short period (number of consecutive random numbers generated without repetition): the exact period depends on the initial seed used, but appears to be somewhere in the thousands. This is due to implementation issues in the API. An alternate generator with a much longer period can be implemented using API Qc3GenPRNs which is based on the FIPS 186-1 algorithm. This API is primarily intended for cryptography support but will still work even if this support is not installed. Qc3GenPRNs produces a pseudo-random binary stream whose length is measured in bytes; for applications currently using CEERAN0, Qc3GenPRNs' output has to be normalized to the (0,1) range: this makes the change in generation algorithm transparent to the applications. The following ILE IBM® RPG/400® example illustrates the invocation of Qc3GenPRNs and the normalization technique.
Note: This general approach may be ported to ILE C/C++ but will not work with ILE COBOL. The normalization technique relies on unsigned integers which, as of V5R2, are not supported in ILE COBOL. However, a generator/normalizer module or service program may be coded in ILE RPG or ILE C/C++, then bound to an ILE COBOL program.
*****************************************************************
* This program generates pseudo-random floating-point numbers
* in the (0,1) range, which are written to a database file.
* The program invokes API Qc3GenPRNs to generate the numbers.
* Qc3GenPRNs is based on the FIPS 186-1 algorithm, and is
* primarily intended for cryptographic use. However,
* applications can be designed to normalize the APIs output
* to the (0,1) range; an example of this technique is shown
* in the program.
* Qc3GenPRNs has a companion API Qc3AddPRNGSeed, which is
* used to add seed into the system seed digest. This
* program does not use the latter API, therefore the seed
* digest is populated by default using system information.
*
* Compile this program with:
*
* CRTRPGMOD MODULE(member_name)
*
* CRTPGM PGM(module__name) BNDSRVPGM(QC3PRNG)
*
* where QC3PRNG is the service program exporting the two APIs.
*
*****************************************************************
*
* Physical file to store the random numbers generated.
*
Ffipspf O E DISK
*****************************************************************
*
* Definitions of standard data types.
*
D StdInt S 10I 0 integer
*
* The next 3 data types are explained in more detail in the
* documentation for Qc3GenPRNs.
*
D StdBinStream S 8A binary stream
D StdType S 1A type
D StdParity S 1A parity
*****************************************************************
*
* Standard error structure definition (see
* QSYSINC/QRPGLESRC/QUSEC.
*
D QUSEC DS
D QUSBPRV 1 4B 0
D QUSBAVL 5 8B 0
D QUSEI 9 15
D QUSERVED 16 16
*
* Provide 100 bytes of storage for the API to return error
* information.
*
D QUSED01 17 116
*****************************************************************
*
* Prototype for API Qc3GenPRNs. See API documentation for
* additional details.
*
D fips186_1 PR EXTPROC('Qc3GenPRNs')
D parm1 LIKE(StdBinStream)
D parm2 LIKE(StdInt)
D parm3 LIKE(StdType)
D parm4 LIKE(StdParity)
D parm5 LIKE(Qusec)
*****************************************************************
*
* Data structure ds1 is intended to contain the output from
* Qc3GenPRNs. Two overlaying subfields are defined: var1a is
* of type character, as the API requires; var1u is an unsigned
* integer, for later numerical processing.
*
D ds1 DS
D var1a 1 8A
D var1u 1 8U 0
*
* Length of PRN data receiver var1a.
*
D var2 S LIKE(StdInt)
*
* PRN type.
*
D var3 S LIKE(StdType)
*
* PRN Parity.
*
D var4 S LIKE(StdParity)
*
* Variable to contain divisor for normalization.
* var6a is needed for initialization (see below).
* var6u is used for numerical processing.
*
D ds6 DS
D var6a 1 8A
D var6u 1 8U 0
*
* Counter for loop to generate random numbers.
*
D counter S LIKE(StdInt)
*
* Number of iterations/random numbers to generate.
*
D n C CONST(100)
*****************************************************************
*
* Initialize divisor to largest 8-byte unsigned integer
* ((2 ** 64) - 1).
* This is hexadecimal
* FFFFFFFFFFFFFFFF
* or decimal
* 18446744073709551615
*
C eval var6a = X'FFFFFFFFFFFFFFFF'
*
* Provide the API with 100 bytes to return error data in case
* of failure.
*
C eval QUSBPRV = 100
*
* Initialize bytes available. Qc3GenPRNs will change this to a
* a non-zero value in case of failure.
*
C eval QUSBAVL = 0
*
* Set length of PRN data receiver.
*
C eval var2 = %len(var1a)
*
* Set PRN type to '0' (generate real pseudorandom numbers).
*
C eval var3 = '0'
*
* Set PRN parity to '0' (do not set parity in the binary stream).
*
C eval var4 = '0'
*
* Generate n random numbers.
*
C for counter = 1 by 1 to n
*
* Invoke API for next random number.
*
C callp fips186_1(var1a:var2:var3:var4:QUSEC)
*
* Normalize the API's output to the (0,1) range. The output is
* treated as an 8-byte unsigned integer; dividing it by
* ((2 ** 64) - 1) reduces it to the desired range.
* The normalized value is assigned to the appropriate field in
* the file buffer.
*
C eval fipsfld = var1u / var6u
*
* Write random number to the output file.
*
C write fipsrec
C endfor
*
* End program.
*
C eval *inlr = *on
*****************************************************************
The file fipspf is defined with the following DDS:
* COMPILE THIS FILE WITH SIZE(*NOMAX)
A R FIPSREC
A FIPSFLD 17F 7 FLTPCN(*DOUBLE)
Historical Number
28281720
Was this topic helpful?
Document Information
Modified date:
18 December 2019
UID
nas8N1016809