Great, although I donāt understand the algorithm.
My algorithm uses the fact that e=2 is a prim element (not sure if this is the correct translation, in German it is named āprimitives Elementā) of the big prim number (p=2147483629). This was quite probabil because p is 5 mod 2 and I proved it with another program. Such a prim element has the property that it runs through all numbers in the modules (but not 0) if you take
e^^0, e^^1, e^^2, ā¦, e^^(p-2)
e^^(p-1) = e^^0 = 1 (mod p) again which closes the circle.
It can of cause never be 0 because p is prim.
As input I take an independent variable +RAND which is in the range from 1 to p-1. If it is 0, the routine is called for the first time and I derive a value from the timestamp.
Then I multiply the value n-times with 2 where n (1-255) is also derived from the timestamp. The multiplication with 2, maps the values to any other value from 1 to p-1 and by repeating it randomly, I receive any random value x in the range from 1 to p-1.
The random value returned is then (x-1) / (p-1)
I only searched in 2003 an easy to use algorythm to implement in Natural and found this one. I want it to use to get random records from an Database to print some records for the controlling department.
this is probably an absolute newbie question, sorry for that, but maybe you can give me a hint nevertheless:
I experimented with your random-function and reworked it into a subprogram to be able to use it on the mainframe too. I keep getting very puzzling results, though - in short: it seems to work on PC but not on the mainframe!? :? I copied both the subprogram and the calling program from my PC-environment to my library on the mainframe so I am using the exact same coding. On PC I get a desired series of pseudo-random numbers, on the mainframe (IBM Host, z/OS), however, I get the same number over and over again. I assume this has to do with the F8 format (or the conversion F8 to I4 ) - does that work differently on the mainframe???
Hereās your function as subprogram (I added some āwritesā for testing):
* (Pseudo-) Zufallszahl
*
* Function .... RAND
* Author ...... Lukas Hundemer
* Last edit ... 2006-07-20
* Copyright ... Software AG 2006. All rights reserved.
*
* Description
* Returns random number 0 <= RAND < 1
*
* Note
* It uses the independent variable +RAND when called iple times
*
* Anmerkung: Da Funktionen und Funktionsaufrufe auf dem HOST (NAT 4)
* nicht implementiert sind, habe ich die Funktion in ein
* Subprogram umgewandelt.
*
* ************************************************************************************
DEFINE DATA
PARAMETER
1 #RAND-F8 ( F8 )
LOCAL
1 #PRIM (I4) INIT <2147483629> /* big I4 prim number, 2 as prim element
1 #P1 (I4) /* p-1
1 #PH (I4) /* (p-1)/2
1 #VAL (I4)
1 #VAL1 (I4)
1 #STCL ( B8 )
1 REDEFINE #STCL
2 #S1 (B2)
2 #T4 (I4) /* random start if required
2 REDEFINE #T4
3 #T4A (B3)
3 #T1 (B1) /* 0 - 255 random repeat
2 #S2 (B2)
1 #R2 (I2)
1 REDEFINE #R2
2 #R21 (B1)
2 #R22 (B1)
1 #I (I4)
1 #J (N4)
1 #F ( F8 )
INDEPENDENT
1 +RAND (I4)
END-DEFINE
*
#P1 := #PRIM - 1
#PH := #P1 / 2
MOVE *TIMESTMP TO #STCL
*
IF +RAND = 0 /* first call
MOVE #T4 TO #VAL /* random time
IF #VAL >= #P1 /* mod p-1
#VAL := #VAL - #P1
ELSE
REPEAT
IF #VAL >= 0
ESCAPE BOTTOM
ELSE
#VAL := #VAL + #P1
END-IF
END-REPEAT
END-IF
+RAND := #VAL + 1 /* range 1 to p-1
END-IF
*
#VAL := +RAND
WRITE *PROGRAM '=' #VAL '=' +RAND
RESET #R22
MOVE #T1 TO #R21 /* get unsigned (i1)
*
FOR #I = 1 TO #R2 /* ** rand(i1)
IF #VAL > #PH /* 2 * #val > p
#VAL1 := #PRIM - #VAL /* avoid overflow
#VAL := #VAL - #VAL1 /* = v-(p-v) = 2v-p = 2v (mod p)
ELSE
ADD #VAL TO #VAL
END-IF
END-FOR
*
MOVE #VAL TO +RAND
#F := #VAL - 1
WRITE *PROGRAM '=' #F
#RAND-F8 := #F / #P1
*
END
Hereās the calling PGM:
DEFINE DATA LOCAL
1 #RUECK ( F8 )
1 #CNTR (I2)
1 #RUECK-I4 (I4)
END-DEFINE
*
FOR #CNTR = 1 TO 8
CALLNAT '#DHRANDN' #RUECK
#RUECK-I4 := 10 * #RUECK + 1
PRINT '=' #RUECK '=' #RUECK-I4
END-FOR
*
END
The function was designed for PC. To bring it on the mainframe is no big deal.
The problem which you found comes from the byte-swapping on the PC and the fact that my program uses redefined binary fields (not well designed when you go to other platforms :oops: ).
The main part which redefines the time still works because it redefines the middle 4 bytes of the 8 byte binary time. And the middle remains the middle
The part which does not work, is the conversion from the 1 byte unsigned binary to an integer. Just replace the lines
playing around with ānewā functions like REQUEST DOCUMENT I wrote a small program that fetches true random numbers from the website www.random.org - they claim that their numbers are generated from atmospheric noise and thus truly random - as opposed to algorithm-generated pseudo-random numbers.
** request n random numbers from www.random.org
**
************************************************************************
**
DEFINE DATA
LOCAL
1 #IN-URL (A) DYNAMIC INIT <'http://www.random.org/integers/'>
1 #HEADER_STATUS (A253)
1 #HEADER_CONTENT_TYPE (A253)
1 #HEADER_LOCATION (A253)
1 #HEADER_AUTHENTICATE (A) DYNAMIC
1 #RETURN_HEADER (A) DYNAMIC
1 #RETURN_PAGE (A) DYNAMIC
1 #RESPONSE (I4)
1 #ERROR-NUM (I4)
1 #NUM (I4) INIT <10> /* how many randoms?
1 #MIN (I4) INIT <1> /* smallest random
1 #MAX (I4) INIT <9999> /* largest random
1 #RANDOM-ARRAY (A4/1:*)
1 #I (I4)
1 #LF (A1) CONST <H>
/* that should read H'0A' of course - the forum editor is taking away the hex-string??
END-DEFINE
*
** for more options see www.random.org
COMPRESS #IN-URL '?num=' #NUM '&min=' #MIN '&max=' #MAX
'&col=1&base=10&format=plain&rnd=new' INTO #IN-URL LEAVING NO
**
RESET #RETURN_HEADER #RETURN_PAGE
RESET #RESPONSE #ERROR-NUM
**
REQUEST DOCUMENT FROM #IN-URL
RETURN HEADER ALL #RETURN_HEADER
NAME ' ' VALUE #HEADER_STATUS
NAME 'Content-Type' VALUE #HEADER_CONTENT_TYPE
NAME 'Location' VALUE #HEADER_LOCATION
NAME 'WWW-authenticate' VALUE #HEADER_AUTHENTICATE
PAGE #RETURN_PAGE ENCODED CODEPAGE ' '
RESPONSE #RESPONSE
GIVING #ERROR-NUM
**
IF #ERROR-NUM GT 0 /* Natural error occurred
IF #ERROR-NUM = 8301 /* Wrong Url was entered
WRITE 'NAT8301 Wrong URL syntax.'
ELSE
COMPRESS 'Natural error NAT' #ERROR-NUM ' occurred.'
INTO #RETURN_HEADER LEAVING NO
WRITE #RETURN_HEADER (AL=79)
END-IF
ESCAPE ROUTINE
END-IF
**
** separate output into array
**
ADD 1 TO #NUM /* one element more than numbers returned
EXPAND OCCURRENCES OF ARRAY #RANDOM-ARRAY TO (1:#NUM)
SEPARATE #RETURN_PAGE INTO #RANDOM-ARRAY(*) WITH DELIMITER #LF
**
SUBTRACT 1 FROM #NUM
RESIZE OCCURRENCES OF ARRAY #RANDOM-ARRAY TO (1:#NUM)
*
FOR #I 1 #num /* or: 1 to *OCC(#RANDOM-ARRAY)
PRINT #RANDOM-ARRAY(#I)
END-FOR
**
END
**
Notes:
there is only a LF (Hā0Aā) in the return-string, not a CRLF (took some time to figure that out) :?
if an x-array is used as recieving field it must be instantiated with a number at least one greater than the number of randoms received, otherwise it wouldnāt work (NAT1313)
Iām not a math boffin but based the following subroutine on some web-site info I found. It looks shorter, but perhaps it does not work properly?
* Generates next pseudo-random number X based on last one
* If zero is passed in then it is based on some bytes from *timestamp.
DEFINE DATA
PARAMETER
1 #RANDOM-NUMBER (P11.7) BY VALUE RESULT
LOCAL
1 #A (P11.7) CONST <16807>
1 #Y (P11.7)
1 #M (P11) CONST <2147483647>
1 #TIMESTMP (B8)
1 REDEFINE #TIMESTMP
2 FILLER (A4)
2 #TIMESTMP-I (I4)
1 #TIMESTMP-N (N10.7)
1 REDEFINE #TIMESTMP-N
2 FILLER (A7)
2 #SEED (N3.7)
END-DEFINE
DEFINE RANDOM
REPEAT WHILE #RANDOM-NUMBER = 0
#TIMESTMP := *TIMESTMP
#TIMESTMP-N := ABS(#TIMESTMP-I)
#RANDOM-NUMBER := #SEED
END-REPEAT
COMPUTE ROUNDED #Y := #A * #RANDOM-NUMBER
DIVIDE #M INTO #Y GIVING #Y REMAINDER #RANDOM-NUMBER
END-SUBROUTINE
END