User Tools

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
        add  ecx,991
        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
This website uses cookies for visitor traffic analysis. By using the website, you agree with storing the cookies on your computer.More information
generating_20pseudo-random_20numbers.txt · Last modified: 2018/04/13 10:43 by richardrussell