IGNORED

# RND RND and RAND: Pseudorandom Number Generation by TI Basic

## Recommended Posts

Because this topic has surfaced in several threads on this forum, I decided to give it its own thread and explain in great detail how TI Basic’s RND function and the GPL RAND function it calls 7 – 69 times work.

GPL RAND function—

RAND takes a one-byte argument (lim) that represents the limit of the pseudorandom number (PRN) that is to be returned to the caller in >8378. RAND first generates a 16-bit PRN from the seed value (16 bits) in >83C0 as follows:
`PRN = SEED * 28645 + 31417`

RAND then stores the PRN thus generated back into >83C0 as the new seed. RAND next adds 1 to the limit value it was passed to use as the modulus to operate on the PRN just generated after its bytes are swapped (now PRN'). The number returned in >8378 = PRN' modulo (lim+1).

Here is the code for GPL RAND (coded in TMS9900 Assembler in Console ROM 0:
```*-------- GENERATE A PSEUDORANDOM NUMBER ----------
*
WKSC   EQU  >83C0             ISR workspace (R0 = PRN SEED)
WKSE   EQU  >83E0             GPL workspace
R5LSB  EQU  WKSE+R5+R5+1      low byte of R5 of GPL WS
RANDOM EQU  >8378             return location for RAND's PRN return byte

RAND   LI   R4,>6FE5          28645 to R4
MPY  @WKSC,R4          SEED * 28645
AI   R5,>7AB9          PRN = SEED * 28645 + 31417
MOV  R5,@WKSC          PRN is stored as new SEED in >83C0
MOVB *R13,R6           load limit number (byte) from caller to R6
SRL  R6,8              shift to LSB
INC  R6                make modulus (lim+1)
CLR  R4                clear upper half of dividend
SWPB R5                swap bytes of PRN to get PRN'
DIV  R6,R4             perform division by modulus (lim+1)
MOVB @R5LSB,@RANDOM    store LSB of remainder in >8378

TI Basic RND function—

RND takes no arguments and generates a pseudorandom number (PRN) as an 8-byte, radix-100, floating point number (0 <= PRN < 1) and stores it at FAC (>834A). RND calls GPL RAND at least 7 times, once for each radix-100 digit in the significand (7 significant radix-100 digits in mantissa) and as much as 69 times, which is extremely unlikely. RND calls RAND with a limit of 99, which is the highest value possible for a radix-100 digit.

The first PRN digit of the significand is in a loop that insures it will not be 0 unless 63 zeros in a row are returned (extremely unlikely), in which case a floating point 0 is returned as the resulting PRN.

For each time through the first-digit loop that returns 0, the excess-64 exponent that started at >3F (-1 actual exponent) is decremented by 1 and another PRN is generated. This continues until either a non-zero digit is returned or the excess-64 exponent gets to 0 (-64 actual), in which case RND exits with a floating point 0 in FAC.

If a non-zero digit is returned, that becomes the first radix-100 digit of the significand. RND then continues to get the remaining 6 radix-100 digits of the floating point number before returning to the caller.

Here is the code for TI Basic RND (coded in GPL in Console GROM 2) from Heiner Martin’s GPL disassembly [Note that, where there are 2 operands, the order is destination,source.]:
```RND   ST    @>834A,>3F        radix-100 exponent = -1 to FAC
ST    @>8310,>4B        loop counter for significand starting at FAC+1
RND1  RAND  >63               get random radix-100 digit to >8378
CZ    @>8378            0?
BR    GROM@RND3         no, keep current exponent and go on
DEC   @>834A            decrement exponent in FAC
CZ    @>834A            0?
BS    GROM@RND4         exit with 0 as random number
BR    GROM@RND1         back to exponent manipulation
RND2  RAND  >63               get random radix-100 digit to >8378
RND3  ST    *>8310,@>8378     all 7 radix-100 digits (FAC+1 to FAC+7)
CEQ   @>8310,>51        till >8351 (FAC+7)
BS    GROM@RNDX         exit if beyond end of number
INC   @>8310            increase loop counter
BR    GROM@RND2         back to get next random digit
RND4  CLR   @>834B            set 0
```

An ALC translation of the above GPL code for the TI Basic RND function follows in the spoiler:

Spoiler
```*==RND from TI Basic=======================================================*
* RND is functionally equivalent to TI Basic's GPL RND. RND stores its     *
* floating point result in FAC as 0 <= FAC < 1. R0 is used to get PRN from *
* RAND. Avoid R4,R5,R6, which the called RAND uses.                        *
*==========================================================================*
*
RND    MOV  R11,R8            save return
LI   R7,>003F          radix-100 exponent = -1
LI   R1,FAC            destination
RND1   BL   @RAND             get random radix-100 digit to R0
DATA 99
JNE  RND2              keep current exponent and go on
DEC  R7                decrement exponent
JEQ  RND5              exit with 0 as random number
JMP  RND1              back to exponent manipulation
RND2   SWPB R7                get exponent to MSB
MOVB R7,*R1+           copy exponent to FAC..inc to FAC+1
LI   R2,7              counter for 7 radix-100 digits
JMP  RND4              store first digit
RND3   BL   @RAND             get random radix-100 digit to R0
DATA 99
RND4   MOVB R0,*R1+           store next radix-100 digit
DEC  R2                done?
JNE  RND3              no..get next PRN
RND5   CLR  @FAC              set PRN to 0

*-----------------------------------------------------------------
*-- RAND is functionally equivalent to Console ROM 0's ALC for GPL
*-- RAND, except that input is via *R11+ instead of *R13 and output
*-- is MSB of R0, rather than the byte at RANDOM (>8378).
*-----------------------------------------------------------------
*------ Generate A Pseudorandom, Centimal Number in R0 MSB -------
*-----------------------------------------------------------------
WKSC   EQU  >83C0             ISR workspace (R0 = PRN SEED)
WKSE   EQU  >83E0             GPL workspace
R5LSB  EQU  WKSE+R5+R5+1      low byte of R5 of GPL WS

RAND   LI   R4,>6FE5          28645 to R4
MPY  @WKSC,R4          SEED * 28645
AI   R5,>7AB9          PRN = SEED * 28645 + 31417
MOV  R5,@WKSC          PRN is stored as new SEED in >83C0
MOV  *R11+,R6          get maximum byte-value to be returned
SB   R6,R6             clear MSB, insuring R6 < 256
INC  R6                make it a modulus (max+1)
CLR  R4                clear upper half of dividend
SWPB R5                swap bytes of PRN to get PRN'
DIV  R6,R4             perform division by modulus (lim+1)
MOVB @R5LSB,R0         LSB of remainder to MSB of R0
RT      Return random centimal digit to caller```

...lee

Edited by Lee Stewart
##### Share on other sites

Great explanation Lee! I saved this for future reference. Thanks!

##### Share on other sites

• 6 years later...

To round out this discussion, I added my ALC for TI Basic’s RND function to the first post. It may be a little easier to follow for those unfamiliar with GPL.

...lee

##### Share on other sites

Posted (edited)

TI was having fun with this as hex >63 = 99 Decimal or Integer.

And the above listing would never work i.e.

BR GROM@RND3

the real GPL code could would be

BR RND3

or

BR G@RND3

Also the GPL code above is mostly backwards like you would see with GPL disassembly.

ST   >4B,@>8310 is correct the above listing is wrong and would not work.

Edited by RXB
##### Share on other sites

On 5/13/2024 at 12:29 PM, RXB said:

Also the GPL code above is mostly backwards like you would see with GPL disassembly.

ST   >4B,@>8310 is correct the above listing is wrong and would not work.

The above GPL does just fine to explain what is going on to the reader. It is Heiner Martin’s disassembly and his comments. I prefaced it with an explanation that, where 2 operands are shown, their order is destination,source. Furthermore, I believe at least one GPL assembler (Reis-Ware), in fact, puts the operands in that order. Even though the use of “GROM” instead of “G” for addresses will not assemble as is (even in Reis-Ware), it does help to make obvious to the GPL incognoscenti that the address is in GROM. At any rate, my principal plan was always to translate it to ALC, which I did 2 days ago and that ALC, indeed, assembles correctly.

...lee

##### Share on other sites

• 4 weeks later...

Hi All,

I am looking through a lot of my own coding from the 80's, I was wondering what the reason I had to chose this memory location and added code for a random number, I hope you guys could enlighten me on the choices I made back in the day. Regards Arto.

1600 SUB R1(Z):: RANDOMIZE :: CALL PEEK(-31880,Z):: Z=INT(Z/2.22)+1 :: SUBEND

##### Share on other sites

1 hour ago, Artoj said:

Hi All,

I am looking through a lot of my own coding from the 80's, I was wondering what the reason I had to chose this memory location and added code for a random number, I hope you guys could enlighten me on the choices I made back in the day. Regards Arto.

1600 SUB R1(Z):: RANDOMIZE :: CALL PEEK(-31880,Z):: Z=INT(Z/2.22)+1 :: SUBEND

Well...presuming this is XB, the location -31880 (>8378) is the radix-100 byte returned by the GPL RAND instruction, which is called 4 times by XB’s RANDOMIZE. The value returned by PEEK to Z would be from that fourth call to RAND. Z will have a value from 0 to 99. The result of the calculation will be from 1 to 45.

...lee

• 3
• 1
##### Share on other sites

7 hours ago, Lee Stewart said:

Well...presuming this is XB, the location -31880 (>8378) is the radix-100 byte returned by the GPL RAND instruction, which is called 4 times by XB’s RANDOMIZE. The value returned by PEEK to Z would be from that fourth call to RAND. Z will have a value from 0 to 99. The result of the calculation will be from 1 to 45.

Thanks a heap Lee,

That was a clear explanation, this also clarifies my code, I was looking for min/max for the random number choice. I vaguely remember using this after it was commented upon in one of the TI club news letters back in the 80's. Regards Arto.

## Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

×   Pasted as rich text.   Paste as plain text instead

Only 75 emoji are allowed.