# A random number generator routine...?

Hello!

I'm a beginner at assembly language (x86) and would like to know how to code a routine that generates a random number out of any given range (Example: a random number from 0 to 99).

I'm using Macro assembler, and I've found a couple of routines here and there, but they're far too complicated for me at the moment. I want something I can sink my teeth into... Something I can understand fully in order to create something of my own in the future...

Hope someone can help me here... Thanks in advance!

• [green]
Computers don't do random very well. I checked the RAND proc below
by counting each occurance of every number 0-255 and it produced an even
amount of each number (except 38?) in 8000 rand's or so, with no appearant pattern.
Then when I used it to make a mixed up Vmode3 attribute screen I noticed some patterns in the 16 background colors?
I didn't check AX=word for rand accuracy, & I didn't check it on other computers either. But it's free.............AND Nasm toooooooo
[/green]
[code]
; ========================= RANDOM.INC =========================
; Call with, NOTHING

; Returns, AL = random number between 0-255,
; AX may be a random number too ?
; DW RNDNUM holds AX=random_number_in AL
SEED DW 3749h
RNDNUM DW 0
align 16
RANDOM:
PUSH DX
MOV AX,[SEED] ;; AX = seed
MOV DX,8405h ;; DX = 8405h
MUL DX ;; MUL (8405h * SEED) into dword DX:AX
;
CMP AX,[SEED]
JNZ GOTSEED ;; if new SEED = old SEED, alter SEED
MOV AH,DL
INC AX
GOTSEED:
MOV WORD [SEED],AX ;; We have a new seed, so store it
MOV AX,DX ;; AL = random number
MOV WORD [RNDNUM],AX
POP DX
RET
[/code]

• : Then when I used it to make a mixed up Vmode3 attribute screen I noticed some patterns in the 16 background colors?

You will always notice patterns if you run a computer RNG long enough, because it always repeats the same sequence. One way to break up patterns, if you're waiting for user input, is to run the RNG constantly off a timer interrupt, then take whatever is the current result when the input occurs. This way you have a truly random event (the user reaction time) picking one point out of a psuedo-random set. This is how slot machines do it.

Here's a respectable 32 bit linear regression RNG. The basic algorithm is:

RND(n+1) = (a*RND(n) + c) mod M

where in this case a=19660Dh, c=3C6EF35Fh and M is 2^32. If you want an 8-bit random number take the lower 8 bits, for a 16-bit the lower 16, etc.

[code]
.DATA
align 4
random_32 label dword
dd 0ffffffffh ; any seed except 0

.CODE
random proc
push edx
mov eax,[random_32]
mov edx,0019660Dh
mul edx
mov [random_32],eax
pop edx
ret
random endp
[/code]

It would take a lot of space to explain why it's good, or how those particular numbers a and c were chosen. I got it originally from Knuth, Art of Computer Programming, volume 2, where you can read the explanation yourself if you're so inclined. It's not worth buying the book but you can find it in most academic libraries.

To get an integer random number in the range 0..K, first get yourself a binary N-bit random number in the range 0..2^N-1 - ie for 16 bits, in the range 0000-FFFF. Then multiply this by (K+1) with an NxN bit multiply. The high half of the product is your random integer.

Eg for an integer random number in the range 0..51 - useful for card games - using the above 32 bit RNG:

[code]
push edx
call random ; new random in EAX
mov edx,52 ; N+1 in EDX
mul edx ; multiply
pop edx
[/code]

• The timer running Rand constantly is great info......Thankx

I'm thinking an 18.2065hz hook INT 1Ch routine timer that also increments a couple declaired Dwords in the .asm might work ok.

But that only gives 18 rands per second & if the program requires
many rands in a short period of time to update data then moves on to
other processes in the loop, some kind of rand storage might be required
like a rotateing buffer update????

Bitdog

• : The timer running Rand constantly is great info......Thankx
:
: I'm thinking an 18.2065hz hook INT 1Ch routine timer that also increments a couple declaired Dwords in the .asm might work ok.
:
: But that only gives 18 rands per second & if the program requires
: many rands in a short period of time to update data then moves on to
: other processes in the loop, some kind of rand storage might be required
: like a rotateing buffer update????

Well it depends how good you want your random numbers to be. If you use a proper generator like the one I described, you can just make successive calls to get as many random numbers as you want, but you run into the problem of sequential correlation, where each number depends in some predictable way on the previous. Like, if rand(N) is very small, rand(N+1) may also be smaller than average.

There is a thing called a Bays-Durham Shuffle to get round this. Basically you make a table in RAM of (say) 32 dwords, and initialize it with the results of 32 calls to the RNG. After that, every time you call the RNG you use the result to make an index into the table (with a simple bit mask). You go to the indexed location and take the random number stored there. Then you replace that number in the table with the one you just got from the RNG. This way, each number you take is (on average) 32 RNG calls away from the previous and sequential correlation disappears.

• : There is a thing called a Bays-Durham Shuffle to get round this. Basically you make a table in RAM of (say) 32 dwords, and initialize it with the results of 32 calls to the RNG. After that, every time you call the RNG you use the result to make an index into the table (with a simple bit mask). You go to the indexed location and take the random number stored there. Then you replace that number in the table with the one you just got from the RNG. This way, each number you take is (on average) 32 RNG calls away from the previous and sequential correlation disappears.

[green]
I like that, & you got me thinking. What if:
256 rand numbers were made sequentially, stored in a table,
and if a random number was needed, the tick byte at 0040:006C
could be the referance offset into the table, a rand is recieved & it's address is saved,
The next time you need a rand, you do the same to get rand,
but swap your last rand with the new one.
You always have the same rands in the table, but their order is altered constantly, and the rand you get depends on the 18.2065hz tick number.
If you get some quick sequential numbers, they probably arn't the same
as the last time you got the same amount of numbers from the same address.

The use rand proc to make a table ONCE saves a lot of Rand divide time (your idea)
The use CPU's clock to get a rand (your idea)
& a table can be quickly access by
XOR BH,BH
MOV BL,[0000:046Ch]
SHL BX,1 ;(size of rand) (no shift for byte, SHL 1=word, SHL 2=Dword