Any body got a method for generating a random number?
Like for shuffling a set of cards or rolling dice.
I believe i saw someone post something like that on the old board.

thanx a gig:o
Posted on 2001-08-14 16:50:49 by titan
push the limit and call it, eax return a rnd between 0..limit-1

somebody told me once its similar to the rnd routine used by psx videogame...


push ebp ecx edx
mov eax, [pseed]
mov ecx, 41c64e6dh
mul ecx
add eax, 3039h
and eax, 7ffffffh
mov [pseed], eax
mov ecx, [esp+(4*3)+4]
sub edx, edx
div ecx
xchg eax, edx
pop edx ecx ebp
ret 4

Posted on 2001-08-14 17:20:55 by ancev

This very good random number generator is written by Wiz Kid
I only suggest you to use it...go to his site etc

It only looks a little complicated because its inside a DLL but the actual function is simple and very powefull ...

;; ;;
;; Whiz Kid Technomagic Random Number Generator ;;
;; ;;
;; Windows 95 DLL ;;
;; ;;
;; Copyright 1998 G. Adam Stanislav ;;
;; All rights reserved ;;
;; ;;
;; Company name: Whiz Kid Technomagic ;;
;; Company e-mail: [email][/email] ;;
;; Web site: [url][/url] ;;
;; ;;
;; Started: 10-Aug-1998 ;;
;; Updated: 11-Aug-1998 ;;
;; ;;
;; Permission is hereby granted to use this DLL with your software under the ;;
;; following conditions: ;;
;; ;;
;; (1) You will not modify it in any way, including but not limited to ;;
;; preserving the copyright notice embeded in the DLL. ;;
;; ;;
;; (2) You will install it in Windows system folder. ;;
;; ;;
;; (3) You will not install it over a later version of this DLL. ;;
;; ;;
;; That is quite simple... ;;
;; ;;
TITLE Whiz Kid Technomagic Random Number Generator
.model flat

option dotname


; Our seed number is 39 bits wide. Our random number is a 32-bit integer
; produced from the 39-bit seed number.
.seed dd 0
db 11101b ; At least one of the 39 bits must be non-zero!


; Microsoft linker gets really cranky if the label of the DLL entry does not start
; with an underline. Other than that, it can be named anything. However, it should
; end with @12, otherwise the linker gives us a warning.
align dword
_dll@12 proc public

mov al, 1 ; Windows is happy when EAX is not 0. To save bytes, we just use AL.
ret 12

_dll@12 endp

;; To make the DLL useful for everyone, we need to supply two procedures for
;; for every function. One that is fast, one that is compatible with Windows 95
;; calling conventions.
;; The fast ones receive their parameters in the CPU registers. These procedures
;; can be called directly only from assembly language programs.
;; The compatible ones receive parameters on the stack. The also need to have
;; their names mangled in strange ways (preceded by an underline, followed
;; by '@' and the number of bytes passed on stack). They also need to clean up
;; the stack. They can be called by programs written in presumably any language.
;; We need to allow the calling program to initialize the seed value. Otherwise,
;; the program would receive the same sequence of pseudo-random numbers every
;; time it runs.
;; We shall name the "compatible" procedure _WktmrngSetSeed@4. In C, it would be
;; declared something like this:
;; unsigned __stdcall WktmrngSetSeed(unsigned);
;; It could be int instead of unsigned. It could also be long or unsigned long
;; (or might have to be, depending on the compiler).
;; The function returns the new seed just set. Or it can be treated as "void."
;; The "Wktmrng" stands for "Whiz Kid Technomagic Random Number Generator."
;; We use it since it is theoretically possible a program may be linked to
;; another DLL which also may contain a SetSeed() function.
;; Of course, we can also place the following in a header file:
;; #define SetSeed WktmrngSetSeed
;; That makes coding simpler.
;; Now, as mentioned above, a "compatible" function must clean its stack.
;; So, the first instinct may be to do something like this:
;; _WktmrngSetSeed@4 proc public
;; push ebp
;; mov ebp, sp
;; mov eax, [ebp+8]
;; call wktmrngsetseed
;; leave
;; ret 4
;; _WktmrngSetSeed@4 endp
;; Of course, that would work, but we can do it much faster. And we will:

; Note: We do not use align dword here. The previous procedure is 5 bytes long,
; this one is 3 bytes long. So this procedure is all within one dword, and the
; next procedure (to which we fall through) is aligned at dword boundary.
_WktmrngSetSeed@4 proc public

;; Input:
;; [ESP+4] = bits 31-0 of new seed
;; Output:
;; EAX = bits 31-0 of new seed
;; Registers changed:

pop edx ; Save return address in EDX
pop eax ; Get new seed in EAX
push edx ; Restore return address on top of the stack

; Notice, no ret here, we are falling through to wktmrngsetseed

_WktmrngSetSeed@4 endp

;; Next we create our "fast" procedure, one that is not concerned with stack
;; parameters and similar plague of high-level languages.
;; We shall name it wktmrngsetseed. Again, we can use a "define" or actually
;; an equ in assembly language programs, like this:
;; extrn __imp_wktmrngsetseed:dword
;; SetSeed equ __imp_wktmrngsetseed
;; Then to call it, just do:
;; mov eax, newseed
;; call SetSeed
;; The assembler will automatically interpret the call as:
;; call dword ptr:__imp_wktmrngsetseed

wktmrngsetseed proc public

;; Input:
;; EAX = bits 31-0 of new seed
;; Output:
;; EAX = same
;; Registers modified:
;; None

mov .seed, eax ; Initialize the lower 32 bits of seed
; Also initialize the rest of it to some fixed number other than 0
mov byte ptr .seed[4], 11101b

wktmrngsetseed endp

;; OK, so how do we produce a random number? Well, we do not. It is not possible
;; to create a truly random number in software alone. What we can do, however,
;; is produce a sequence of pseudo-random numbers.
;; Such a sequence is cyclical. That means that after we have come up with N
;; numbers, the sequence repeats. In other words, the (N+1)st result will be
;; the same as the 1st result, the (N+2)nd result the same as the 2nd result, etc.
;; That does not sound too good, but it is not a problem if N is reasonably
;; large.
;; Entire volumes have been written about producing a pseudo-random sequence
;; using software methods. They typically follow this algorithm:
;; new seed := old seed * A + B
;; random number := new seed
;; In this algorithm A and B are some constants.
;; The volumes that have been written deal mostly with methods of choosing the
;; right values for A and B, so N is reasonably large.
;; This is an OK method for random-number generators written in high-level
;; languages (HLL). But we can do much better in assembly language.
;; Since we are as close to accessing the hardware directly as we can using
;; software methods alone, we will code a method developed by hardware
;; engineers. They use what they call a feedback shift register (FSR). You can
;; read about it in Chapter 9 (pages 655-657) of The Art of Electronics,
;; Second Edition, by Paul Horowitz and Winfield Hill, ISBN 0-521-37095-7.
;; This is a book anyone dealing with computers (and electronics in general)
;; should have anyway.
;; A FSR shifts the seed value one bit to the right. It than XORs the bit
;; shifted out with one or more bits inside the old seed and stores the
;; result in the most significant bit of the new seed (which is also the
;; new random number). The choice of which bit to XOR is beyond the scope
;; of this comment -- you can find it in the book mentioned above.
;; In case of a 39-bit FSR, we must XOR the bit shifted out either with
;; bit 35 or bit 4 of the old seed.
;; The FSR method has several advantages: First, it is very easy to implement
;; in hardware (which makes you wonder why the Intel processor family does not
;; have a built-in random register. More importantly, with the proper choice
;; of bits to XOR, the n of the sequence is very high. For a 39-bit sequence
;; which we are implementing in this DLL, N = 549,755,813,887. Yes, you call
;; the procedure below more than half a trillion times before the sequence starts
;; repeating. That is way bigger than any of the A,B choices in the HLL design
;; mentioned above.
;; The method has one slight problem: If the seed is initialized to 0, the
;; whole sequence degenerates. All remaining "random numbers" will be zeros.
;; By the same token, the sequence will never produce a zero in all bits
;; if initialized to any number but 0. We get around this problem by using
;; a larger than 32-bit sequence, and placing a 1 to some of the higher bits
;; whenever initializing the seed. And because we are only using the other
;; 32 bits for our result, we can also receive a zero as a random number.
;; So, why is it not used in software much? Is it, perhaps, too hard to implement
;; using an HLL? Well, it is very simple with assembly language.
;; In this case, no parameter is passed to our procedure. That means that
;; our "compatible" function and fast funtion are one and the same.
;; The assembler lets us assign any number of names to the same procedure,
;; so we will name it _WktmrngGetRandomNumber@0 for HLL programs and
;; wktmrnggetrandomnumber for assembly language program (just to be
;; consistent with the nameing convention of the above procedures.
;; In C, we can declare it as:
;; unsigned WktmrngGetRandomNumber(void);
;; #define GetRandomNumber WktmrngGetRandomNumber
;; In assembly language:
;; extrn __imp_wktmrnggetrandomnumber:dword
;; GetRandomNumber equ __imp_wktmrnggetrandomnumber
align dword

_WktmrngGetRandomNumber@0 proc public
wktmrnggetrandomnumber proc public

;; Input:
;; None
;; Output:
;; EAX = 32-bit pseudo-random number
;; Registers modified:
;; EAX

; Save registers used for anything but return value
push ecx
push edx

; Move bits 31-0 of old seed to EAX
mov eax, .seed
; Move bits 38-32 of old seed to DL, set DH = 0
movzx edx, byte ptr .seed[4]
; Shift bits 32-1 to bits 31-0
shrd eax, edx, 1
; Save bits 31-0 of new seed
mov .seed, eax

; Store bit 0 of OLD seed in DH
adc dh, 0 ; DH = bit shifted out of EAX
; Shift bits 38-33 of old seed to bits 37-32
shr dl, 1
; Get bit 35 of old seed to the lsb of CL
mov cl, dl
shr cl, 2
and cl, 1 ; CL = bit 35 of old seed
xor dh, cl ; xor it with old bit 0
shl dh, 6
or dl, dh ; store it in bit 38 ...
mov byte ptr .seed[4], dl ; ... of new seed

pop edx
pop ecx

; That's all, folks!

wktmrnggetrandomnumber endp
_WktmrngGetRandomNumber@0 endp

end _dll@12

Posted on 2001-08-14 17:45:59 by BogdanOntanu
how about this ?


if u want get a random char, this is nice choice..

al = return char
Posted on 2001-09-03 00:44:53 by c][obo
I wrote a faily decient random function a while ago (based on statical methods i learned in a university course...) It has a very long repeating pattern.. I tested it with "random" x, y pixel cordinates and a "random" color. I used direct X and painted the screen randomly to see its pattern...

If it patterened anyway.. it sucked...
If a overall color developed (other than an off gray) it sucked... (since grey is a sum of equally likely average values in RGB..)

The test was quite good and passed my above tests...

Here is the macro i made out of it...

; Random number generator based on the Real time clock
; and the Park, Miller random number algorithm
; Coded by NaN for WIN32ASM
; May 5, 2001
; rev 2.

push ecx
push edx

ifndef __RAND_BY_NAN__
__RAND_BY_NAN__ equ 1

NaNRand dd ?

db 0fh,31h
shr eax, 2
add eax, 1
mov NaNRand, eax

mov eax, NaNRand
mov edx,0
mov ecx, 127773 ;q
div ecx ; eax == floor( seed / q)
; edx == remainder
SWAP eax, edx
push edx
mov ecx, 16807
mul ecx ; eax = mul of remainder * a
pop edx ; edx == floor of seed/q

SWAP eax, edx
push edx
mov ecx, 2836
mul ecx
pop edx ; edx == mull of rem * a
; eax == mull of seed/q * r

sub edx, eax
mov eax, edx
mov NaNRand, eax ; save next seed
mov ecx, base
mov edx, 0
div ecx
mov eax, edx
pop edx
pop ecx
EXITM <eax>

Basic use is like evey other, eax == rand # between 0-(base -1)

mov hRandNumber, RAND32( 16 ) ; eax == Rand in the set {0,..,15}

I checked out Wiz Kid's version, and to me they *appear* identical in function (since his tests by the same methods), but never put the effort in to clock which is fastest (dont care really). Also, i wrote this while i was still a bit green in the world of MASM so im sure there is an optomization or two in there if you did care..)

Oh ya, here is the SWAP macro.. it exchanges register values... I dont know if its faster than xchang but i got a kick outa how neat it works...

xor M1, M2
xor M2, M1
xor M1, M2

Hope it helps..
Posted on 2001-09-03 01:13:24 by NaN
This modification doesn't use ecx, or the SWAP macro:
	mov eax, NaNRand    

xor edx,edx
push 127773 ;q
div DWORD PTR [esp] ; eax == floor( seed / q)
; edx == remainder
push eax
mov eax, 16807
mul edx ; eax = mul of remainder * a
pop edx ; edx == floor of seed/q

push eax
mov eax, 2836
mul edx
pop edx ; edx == mull of rem * a
; eax == mull of seed/q * r
sub edx, eax
mov eax, edx
mov NaNRand, edx ; save next seed
push base
mov edx, 0
div DWORD PTR [esp]
add esp,8
mov eax, edx
Posted on 2001-09-22 12:00:11 by bitRAKE
Thanx BitRake.... I wrote that when i was still a bit green in MASM coding... Never got around to cleaning it up (dont use it all to often :) ), but thanx again.

Posted on 2001-09-24 01:24:14 by NaN
Another formula is :

Random(j+1) = 16807 * Random(j) mod 2147483647

It can be coded like this :



seed dword 1


; next number

mov eax, seed
mov ebx, 16807
mov ecx, 2147483647
mul ebx
div ecx
mov seed, edx

; result in edx and seed


Posted on 2001-09-24 02:15:16 by Dr. Manhattan
BogdanOntanu, the only problem I have with Whiz Kid's rng is that it uses shift operations and each random number returned depends highly on the previous one. It works great to fill up the screen with random pixels with good distribution but doesn't do too well on the chi square test (basic gist of it is the randomness of each successive # generated isn't very random wrt to the previously generated #. See "Inner Loops" for a more in depth explanation).

A really fast algo that is used a lot is the r250 rng which uses a table of 250 random starting values and then xors two of these values together to return a random #. Of course it has to be seeded with another (simple) random # generator. It runs at 10 clocks / random number and is a fairly decent pseudo rng. Code follows. Btw I think he just used the increment table to save some cycles.

align 4
IL_R250RandomIndex1 dd 0
IL_R250RandomIndex2 dd 103
IL_R250Table dd 250 dup (0)
IL_R250IncrementTable db 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
db 11, 12, 13, 14, 15, 16, 17, 18, 19, 20
db 21, 22, 23, 24, 25, 26, 27, 28, 29, 30
db 31, 32, 33, 34, 35, 36, 37, 38, 39, 40
db 41, 42, 43, 44, 45, 46, 47, 48, 49, 50
db 51, 52, 53, 54, 55, 56, 57, 58, 59, 60
db 61, 62, 63, 64, 65, 66, 67, 68, 69, 70
db 71, 72, 73, 74, 75, 76, 77, 78, 79, 80
db 81, 82, 83, 84, 85, 86, 87, 88, 89, 90
db 91, 92, 93, 94, 95, 96, 97, 98, 99,100
db 101,102,103,104,105,106,107,108,109,110
db 111,112,113,114,115,116,117,118,119,120
db 121,122,123,124,125,126,127,128,129,130
db 131,132,133,134,135,136,137,138,139,140
db 141,142,143,144,145,146,147,148,149,150
db 151,152,153,154,155,156,157,158,159,160
db 161,162,163,164,165,166,167,168,169,170
db 171,172,173,174,175,176,177,178,179,180
db 181,182,183,184,185,186,187,188,189,190
db 191,192,193,194,195,196,197,198,199,200
db 201,202,203,204,205,206,207,208,209,210
db 211,212,213,214,215,216,217,218,219,220
db 221,222,223,224,225,226,227,228,229,230
db 231,232,233,234,235,236,237,238,239,240
db 241,242,243,244,245,246,247,248,249, 0

_IL_DATA ends

_IL_TEXT segment

;void IL_R250RandomSeed_A(long (*rand)())
;Seeds IL_R250Random() using rand() function. Uses 250 32-bit values.
IL_R250RandomSeed_A proc near C public uses esi ebx, rand:dword ; ;
mov IL_R250RandomIndex1,0 ; ;
mov IL_R250RandomIndex2,103 ; ;
mov esi,(250-1)*4 ; ;
.repeat ; ;
call rand ; ;
mov IL_R250Table[esi],eax ; ;
sub esi,4 ; ;
.until SIGN? ; ;
mov eax,0ffffffffH ; ;
mov ecx,80000000H ; ;
lea esi,IL_R250Table+3*4 ; ;
.repeat ; ;
mov edx,[esi] ; ;
and edx,eax ; ;
or edx,ecx ; ;
shr eax,1 ; ;
mov [esi],edx ; ;
add esi,7*4 ; ;
shr ecx,1 ; ;
.until ZERO? ; ;
ret ; ;
IL_R250RandomSeed_A endp ; ;

;long IL_R250Random_A()
;Returns a pseudo-random 32-bit number.
IL_R250Random_A proc near C public uses ebx ; 1;
nop ; 0;for alignment
mov edx,IL_R250RandomIndex1 ; 1;get index 1
mov ecx,IL_R250RandomIndex2 ; 0;get index 2
mov eax,IL_R250Table[edx*4] ; 2;get @ index 1
mov ebx,IL_R250Table[ecx*4] ; 0;get @ index 2
xor eax,ebx ; 1;xor result
mov cl,IL_R250IncrementTable[ecx] ; 0;inc/loop ecx
mov IL_R250Table[edx*4],eax ; 1;save result
mov dl,IL_R250IncrementTable[edx] ; 0;inc/loop edx
mov IL_R250RandomIndex1,edx ; 1;new index 1
mov IL_R250RandomIndex2,ecx ; 0;new index 2
ret ; 3;and return
IL_R250Random_A endp ;;;;10 cycles

Posted on 2002-03-26 01:48:21 by grv575
I just set up and tried vecna's algo and it works fine. Must get around to trying the rest at some time.

Posted on 2002-03-26 06:05:29 by hutch--
For anyone who's interested (and knows C) here's the chi-square test which is one test used to measure the "randomness" of a generator. Just plug in a generator for (*rand)().

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#define IL_RMULT 1103515245
long IL_StandardRandom_seed = 1234567890;

long IL_StandardRandom(void)
unsigned long lo, hi, ll, lh, hh, hl;

lo = IL_StandardRandom_seed & 0xffff;
hi = IL_StandardRandom_seed >> 16;
IL_StandardRandom_seed = IL_StandardRandom_seed * IL_RMULT + 12345;
ll = lo * (IL_RMULT & 0xffff);
lh = lo * (IL_RMULT >> 16 );
hl = hi * (IL_RMULT & 0xffff);
hh = hi * (IL_RMULT >> 16 );
return ((ll + 12345) >> 16) + lh + hl + (hh << 16);

double IL_RandomChiSquareTest(long (*rand)())
unsigned long *ar, n, l, lo, hi;
unsigned char *p;
double sqrsum, chisqr, dev, norm;

ar = calloc(2 * 0x10000, 5);
if (!ar)
return 999999.0; // flags failure
p = (unsigned char *)(ar + 2 * 0x10000);
for (n = 0; n < 10 * 0x10000; n++) {
l = rand();
lo = l & 0xffff;
hi = (l >> 16) | 0x10000;
if (!++p[lo])
ar[lo] += 0x100;
if (!++p[hi])
ar[hi] += 0x100;
for (n = 0; n < 2 * 0x10000; n++)
ar[n] += p[n];
for (n = 0, sqrsum = 0; n < 2 * 0x10000; n++)
sqrsum += ar[n] * (double)ar[n];
chisqr = ((2 * 0x10000 * sqrsum) / (2 * 10 * 0x10000)) - 2 * 10 * 0x10000;
dev = chisqr - 2 * 0x10000;
norm = 2 * sqrt(2 * 0x10000);
return dev / norm;

void main(void)
double tests, off, d;
long (*rand)();

*rand = IL_StandardRandom;
tests = 0;
off = 0;
while (1) {
d = IL_RandomChiSquareTest(rand);
tests += 1;
if ((d <= -1) || (d >= 1))
off += 1;
"Chi square deviation percentage: %3d "
"(15 +/- a few is good; Enter quits)\n",
(int)(100 * off / tests));

Posted on 2002-03-26 13:24:09 by grv575
I have a few misgivings about the assumption that random should end up as a uniform distribution over a large enough sample.

Random is semantic in origin which does not make it a proper mathematical concept so producing uniform distributions over large samples is probably something from a different semantic origin.

With seedable random sequence generators, I would be inclined to go after a system that produced different distributions with different seeds.

I would be interested to hear if anyone else has chewed over this area.

Posted on 2002-03-26 16:57:10 by hutch--
from Main -> Algos & source with all this code floating inside :)
Posted on 2002-03-26 17:00:27 by Hiroshimator
In regard to Hutch's comments as to whether random numbers can be well defined in mathematical terms, I'd refer anyone to the work of Charles Pierce concerning logic and induction. He argued pretty well that any event that appears to have a 50/50 chance of taking place can be safely assumed to be random in as far as no determinate factor can be infered from experience. In other words, a coin toss is as random as anything can get.

I haven't given much thought yet, but I think an interesting approach to a random number generator could make use of that neglected parity flag.
Posted on 2002-03-27 01:21:54 by Canite

I haven't given much thought yet, but I think an interesting approach to a random number generator could make use of that neglected parity flag.
Like RDTSC, this seems like a good idea at first, but taking into account that the execution of the code will have patterns the randomness of the number would be based on the execution path and how often the random numbers are needed. Couple that with the fact that each examination of the parity flag only gives a single bit of data - this hardly seems like a good idea for many random numbers.
Posted on 2002-03-27 01:32:03 by bitRAKE
This is the form that I tested Vecna's version with.

; ##########################

random proc range:DWORD

mov eax, rseed
mov ecx, 41c64e6dh
mul ecx
add eax, 3039h
and eax, 7ffffffh
mov rseed, eax
mov ecx, range
sub edx, edx
div ecx
xchg eax, edx


random endp

; ##########################

SetRandomSeed proc seed:DWORD

rseed dd 0

mov eax, seed
mov rseed, eax


SetRandomSeed endp

; ##########################

What I am looking for is a simple algorithm that delivers a preset range with selected start and finish range so it can be used for things like 500 to 1000. I need it in standard library form so its clean and easy to use for the MASM32 library.

Setting up the range is easy enough, just calculate the specified range, run the algo and add the minimum number in the range to the result.

Any other ideas are welcome.

Posted on 2002-03-27 06:49:54 by hutch--
Agner Fog has put together a libraty which does just that, its really simple to use.
Posted on 2002-03-27 07:16:45 by Eóin
<quote>Like RDTSC, this seems like a good idea at first, but taking into account that the execution of the code will have patterns the randomness of the number would be based on the execution path and how often the random numbers are needed. Couple that with the fact that each examination of the parity flag only gives a single bit of data - this hardly seems like a good idea for many random numbers.

I was considering something that might have a cumulative effect, which would produce an inverse power law distribution similar to the statistics on earth quake magnitudes or stock market bubbles.
Like I said, I haven't given a great deal of thought, but I'll work through it tonight and see if I can code something to clearify my point.
Posted on 2002-03-27 13:02:36 by Canite
Posted on 2002-03-27 21:27:29 by dig