BBC BASIC for Windows provides a pseudo-random number generator for use in BASIC programs but has no built-in support for generating pseudo-random numbers from assembly language programs. This article contains code to add support for generating pseudo-random numbers from assembly language that can be added to any program.

Rand

The following routine generates a 32-bit pseudo-random number when called, the pseudo-random number is returned in the eax register:

.seed dd1:dd0.Rand
moveax, &4C957F2D ; |muldword[seed]; |pushedx; |movedx,[seed]; |imulebx,edx, &5851F42D ; |\ popedx; | - seed = seed * &5851F42D4C957F2Daddedx,ebx; |/movebx,[seed+4]; |imulebx,ebx, &4C957F2D ; |addedx,ebx; |addeax,1; seed = seed + 1adcedx,0mov[seed],eax; store the new seedmov[seed+4],edxshrdeax,edx,21; shift right 21 bitsret; return

Rand(N)

The following routine generates a pseudo-random number in the range 1 to N:

.RandRange
call Rand ; get random numbermovebx,[esp+4]; read range limitxoredx,edx; clear edx registerdivebx; do integer division; eax / ebxmoveax,edx; read remainder of divisioninceax; add oneret4; restore stack and return

Call RandRange using code similar to the following:

push N%call RandRange

The pseudo-random number is returned in eax. Here N% can be a register eax, read from a pointer to a 4 byte block in memory [addr], a BASIC constant N% defined at assemble time, a BASIC variable [^N%] or a numeric constant 1234. If the assembler reports a Size needed error add the dword prefix to the pushed parameter.

To change the range of numbers returned to 0 to N remove the 'inc eax' instruction.

Rand(0)

The following routine generates a pseudo-random number in the range 0.0 to 1.0, exclusive of 1.0:

.RandFloat
call Rand ; get random numberandeax, &7FFFFFFF ; clear top bitpusheax; push random number on stackcall Rand ; get random numberpusheax; push random number on stackpush &80000000; \ Put &8000000000000000push0; / on the stackfildqword[esp]; load &8000000000000000fildqword[esp+8]; load random numberfdivrpst1,st0; divide random number by &8000000000000000fabs; convert result to absolute valuemoveax,[esp+20]; read location to store resultfstpqword[eax]; store resultaddesp,16; free local variablesret4; restore stack and return

To call this routine use code similar to the following:

push ^N#
call RandFloat

The result is stored in the memory pointed to by the parameter. Here ^N# is a pointer to a 64-bit floating point BASIC variable but can be a pointer to an 8 byte block of memory [addr]. If the assembler reports a Size needed error add the dword prefix to the pushed parameter.

Seeding the pseudo-random number generator

The following routine is called to seed the pseudo-random number generator with a 64-bit seed:

.RandSeed
moveax,[esp+4]; load new seedmovedx,[esp+8]movdword[seed],eax; store new seedmovdword[seed+4],edxret8; restore stack and return

To seed the random number generator use the following code:

push hN
push lN
call RandSeed

Here we pass a 64-bit integer value to seed the pseudo-random number, hN is the top 32-bits of the seed and lN is the bottom 32-bits of the seed. By default the seed is set to the value of TIME when the code was assembled. If the assembler reports a Size needed error add the dword prefix to the pushed parameter.

Calling the pseudo-random number generator from BASIC

These routines may be called from BASIC, instead of using the RND function, if you really want to:

result%=USR Rand :REM Return a pseudo-random number in result%SYS RandFloat, ^N#:REM Return a pseudo-random float in N#SYS RandRange, N TO result%:REM Return a range limited pseudo-random number in result%SYS RandSeed, TIME, TIME:REM Seed the pseudo-random generator using TIME

by Jon Ripley, August 2006BBC BASIC for Windowsprovides a pseudo-random number generator for use in BASIC programs but has no built-in support for generating pseudo-random numbers from assembly language programs. This article contains code to add support for generating pseudo-random numbers from assembly language that can be added to any program.## Rand

The following routine generates a 32-bit pseudo-random number when called, the pseudo-random number is returned in the

eaxregister:## Rand(N)

The following routine generates a pseudo-random number in the range 1 to N:

Call RandRange using code similar to the following:

The pseudo-random number is returned in

eax. HereN%can be a registereax, read from a pointer to a 4 byte block in memory[addr], a BASIC constantN%defined at assemble time, a BASIC variable[^N%]or a numeric constant1234. If the assembler reports aSize needederror add thedwordprefix to the pushed parameter.To change the range of numbers returned to 0 to N remove the 'inc eax' instruction.

## Rand(0)

The following routine generates a pseudo-random number in the range 0.0 to 1.0, exclusive of 1.0:

To call this routine use code similar to the following:

The result is stored in the memory pointed to by the parameter. Here

^N#is a pointer to a 64-bit floating point BASIC variable but can be a pointer to an 8 byte block of memory[addr]. If the assembler reports aSize needederror add thedwordprefix to the pushed parameter.## Seeding the pseudo-random number generator

The following routine is called to seed the pseudo-random number generator with a 64-bit seed:

To seed the random number generator use the following code:

Here we pass a 64-bit integer value to seed the pseudo-random number,

hNis the top 32-bits of the seed andlNis the bottom 32-bits of the seed. By default the seed is set to the value of TIME when the code was assembled. If the assembler reports aSize needederror add thedwordprefix to the pushed parameter.## Calling the pseudo-random number generator from BASIC

These routines may be called from BASIC, instead of using the

RNDfunction, if youreallywant to:## References

The multiplier 6364136223846793005 was obtained from Knuth, D.E., "The Art of Computer Programming," Vol 2, Seminumerical Algorithms, Third edition, Addison-Wesley, 1998, p. 106 (line 26) & p. 108.