# BBC BASIC Programmers' Reference

### Site Tools

generating_20pseudo-random_20numbers

## Generating pseudo-random numbers

by Richard Russell, August 2006

BBC BASIC supplies pseudo-random numbers in three formats:

• RND supplies a pseudo-random 32-bit integer
• RND(N) supplies a pseudo-random positive integer in the range 1 to N
• RND(1) supplies a pseudo-random floating-point number in the range 0.0 to 1.0

This article contains routines to provide similar facilities for your assembly-language programs. They are short and very fast, yet the pseudo-random numbers they supply are of an equivalent quality to those supplied by RND.

### RND

The subroutine below provides a direct equivalent to RND. Each time it is called it returns a pseudo-random 32-bit integer in the eax register:

```      .seed
dd 0
db 1
;
; Rnd - return a pseudo-random 32-bit integer
;   Inputs - None
;  Outputs - eax = result
; Destroys - eax, cl, edx, flags
;
.Rnd
mov  eax,[seed]
mov  cl,[seed+4]
mov  edx,eax
shr  cl,1
rcr  edx,1
rcl  cl,1
shl  eax,12
xor  edx,eax
mov  eax,edx
shr  eax,20
xor  eax,edx
mov  [seed+4],cl
mov  [seed],eax
ret```

This subroutine will generate the same sequence of numbers every time it is used. You are likely to want to randomise the sequence in order to make the results less predictable. You can simply do that using the following code, which uses the time as a seed:

```      .Randomise
call "GetTickCount"
mov  [seed],eax
ret```

You can test the code from BASIC as follows:

```        CALL Randomise
FOR I% = 1 TO 20
PRINT ~ USR(Rnd)
NEXT```

### RND(N)

The subroutine below provides a direct equivalent to RND(N), where N is a positive integer greater than 1. Each time it is called it returns a pseudo-random integer in the range 1 to N, in the eax register:

```      ;
; RndRange - return a pseudo-random integer in the range 1 to N
;   Inputs - ebx = N
;  Outputs - eax = result
; Destroys - eax, cl, edx, flags
;
.RndRange
call Rnd
xor  edx,edx
div  ebx
mov  eax,edx
inc  eax
ret```

The parameter N is passed to the subroutine in the ebx register. If you prefer to return a number in the range 0 to N-1 just delete the inc eax instruction.

You can test the code from BASIC as follows:

```        CALL Randomise
FOR I% = 1 TO 20
B% = 100
PRINT USR(RndRange)
NEXT```

### RND(1)

The subroutine below provides a direct equivalent to RND(1). Each time it is called it returns a pseudo-random 64-bit floating-point value (double) in the range 0.0 to 1.0:

```        ;
; RndFloat - return a pseudo-random float in the range 0.0 to 1.0
;   Inputs - ebx = memory address of 64-bit float (double)
;  Outputs - result stored at [ebx]
; Destroys - eax, ecx, edx, flags
;
.RndFloat
call Rnd
bsr  ecx,eax
ror  eax,cl
shld ecx,eax,20
shl  eax,20
mov  [ebx],eax
mov  [ebx+4],ecx
ret```

The value is returned in memory at the address passed in the ebx register.

You can test the code from BASIC as follows:

```        CALL Randomise
FOR I% = 1 TO 20
B% = ^R#
CALL RndFloat
PRINT R#
NEXT``` 