Tvùrce webu je i pro tebe! Postav tøeba web. Bez grafika. Bez kodéra. Hned.
wz

RANDOM.ASM

Random Generator


; =============================================================================
;
;                          Litos - Random generator
;
; =============================================================================
; General algorithm (new_seed = old_seed*214013 + 2531011) for the random
; generator is taken from interpreted BASIC and is described in Microsoft
; Knowledgebase article Q28150. Other possible coefficients are:
; 214013/2531011, 17405/10395331, 214013/13737667, 214013/10395331
;
; Access to global seed of random generator is not SMP locked, it is a random
; number and therefore data distortion is unimportant.
;
; Random numbers in interval are usually calculated with modulo operation.
; Such random numbera are not evenly spreaded out, their density is lower at
; end of the interval. Therefore in this generator is used repeated generation
; of random numbers until suitable number is found, such numbers are spreaded
; evenly in whole interval.
; =============================================================================

		CODE_SECTION	32

; ------------- Macro - shift global random generator with an event

%macro		RNDSHIFT 0
		inc	dword [RandSeed] ; shift global random generator
%endmacro

; ------------- Macro - numeric shift global random generator with an event
; %1 = data to increase random generator

%macro		RNDSHIFTADD 1
		add	dword [RandSeed],%1 ; shift global random generator
%endmacro

; ------------- Macro - next random value (EAX=input/output, destroys EDX)

%macro		RANDNEXT 0
		mov	edx,214013	; coef1
		mul	edx             ; *= coef1
		add	eax,2531011	; += coef2
%endmacro 

; ------------- Macro - next global random value (EAX=output, destroys EDX)

%macro		RANDGNEXT 0
		mov	eax,[RandSeed]; EAX <- seed for global generator
		RANDNEXT		; next random value
		mov	[RandSeed],eax; store new global seed
%endmacro

; ------------- Macro - next global double word (EAX=output, destroys EDX)
; NOTES:	Random number is taken from 2 words instead directly from
;		the seed to avoid prediction of future value of the seed.

%macro		RANDGDWORD 0
		mov	eax,[RandSeed]	; EAX <- seed for global generator
		RANDNEXT		; next random value
		push	eax		; push first random value
		RANDNEXT		; next random value
		mov	[RandSeed],eax	; store new global seed
		pop	edx		; pop first random value
		shr	edx,16		; DX <- second random value
		xchg	ax,dx		; EAX <- random DWORD
%endmacro

; -----------------------------------------------------------------------------
;                           Next random value
; -----------------------------------------------------------------------------
; INPUT:	EAX = old random seed
; OUTPUT:	EAX = new random seed
; -----------------------------------------------------------------------------

RandNext:	push	edx		; push EDX
		RANDNEXT		; next random seed
		pop	edx		; pop EDX
		ret

; -----------------------------------------------------------------------------
;                    Get random byte (with global seed)
; -----------------------------------------------------------------------------
; OUTPUT:	AL = random byte (0 to 255)
; -----------------------------------------------------------------------------

RandByte:	push	edx		; push EDX
		push	eax		; push EAX
		RANDGNEXT		; next global random seed
		shr	eax,16		; EAX <- random word
		xchg	eax,edx		; EDX <- push random word
		pop	eax		; pop EAX
		mov	al,dl		; AL <- random byte
		pop	edx		; pop EDX
		ret

; -----------------------------------------------------------------------------
;                      Get random word (with global seed)
; -----------------------------------------------------------------------------
; OUTPUT:	AX = random word (0 to 65535)
; -----------------------------------------------------------------------------

RandWord:	push	edx		; push EDX
		push	eax		; push EAX
		RANDGNEXT		; next global random seed
		shr	eax,16		; EAX <- random word
		xchg	eax,edx		; EDX <- push random word
		pop	eax		; pop EAX
		xchg	ax,dx		; AX <- random word
		pop	edx		; pop EDX
		ret

; -----------------------------------------------------------------------------
;                  Get random quadruple word (with global seed)
; -----------------------------------------------------------------------------
; OUTPUT:	EDX:EAX = random quadruple word (0 to 0ffffffffffffffffh)
; -----------------------------------------------------------------------------

RandQWord:	call	RandDWord	; generate first random double word
		xchg	eax,edx		; EDX <- first random double word

; RandDWord must follow!

; -----------------------------------------------------------------------------
;                  Get random double word (with global seed)
; -----------------------------------------------------------------------------
; OUTPUT:	EAX = random double word (0 to 0ffffffffh)
; -----------------------------------------------------------------------------

RandDWord:	push	edx		; push EDX
		RANDGDWORD		; generate random double word
		pop	edx		; pop EDX
		ret

; -----------------------------------------------------------------------------
;                  Get random float (9 digits, with global seed)
; -----------------------------------------------------------------------------
; OUTPUT:	ST0 = random float (0 to 1, 0 including, 1 except)
; NOTES:	Maximal value is 0.99999999976716935, prev 0.99999999953433871.
; -----------------------------------------------------------------------------

RandFloat:	push	eax		; push EAX
		xor	eax,eax		; EAX <- 0
		push	eax		; store HIGH dword of the number
		call	RandDWord	; get random double word
		push	eax		; store number to the stack
		fild	qword [esp]	; ST0 <- random number
		fmul	dword [RandFltCoef] ; recalc to range 0 to 1
		pop	eax		; destroy number from the stack
		pop	eax		; destroy HIGH dword from the stack
		pop	eax		; pop EAX
		ret	

; -----------------------------------------------------------------------------
;               Get random double float (18 digits, with global seed)
; -----------------------------------------------------------------------------
; OUTPUT:	ST0 = random double float (0 to 1)
; NOTES:	Due to rounding FPU results, it can reach "1" boundary.
; -----------------------------------------------------------------------------

RandDouble:	push	eax		; push EAX
		call	RandDWord	; get first random double word
		shr	eax,1		; reset signum bit
		push	eax		; store HIGH number to the stack
		call	RandDWord	; get second random double word
		push	eax		; store LOW number to the stack
		fild	qword [esp]	; ST0 <- random number
		fmul	qword [RandDblCoef] ; recalc to range 0 to 1
		pop	eax		; destroy LOW number from the stack
		pop	eax		; destroy HIGH number from the stack
		pop	eax		; pop EAX
		ret	

; -----------------------------------------------------------------------------
;           Get random unsigned byte with max value (with global seed)
; -----------------------------------------------------------------------------
; INPUT:	AL = maximal unsigned value (0 to 255)
; OUTPUT:	AL = random byte (0 to maximal value)
; -----------------------------------------------------------------------------

; ------------- Check maximal value 0

RandMaxByte:	or	al,al		; maximal value is 0?
		jz	RandMaxByte8	; maximal value is 0

; ------------- Push registers

		push	ecx		; push ECX
		push	edx		; push EDX

; ------------- Prepare mask or maximal value

		movzx	edx,al		; EDX <- maximal value
		bsr	ecx,edx		; ECX <- bits of maximal value
		mov	ch,al		; CH <- maximal value
		mov	dl,B1		; DL <- maximal value bit
		shl	edx,cl		; EDX <- maximal value
		dec	edx		; DL <- mask of result

; ------------- Find required value

RandMaxByte2:	call	RandByte	; get random byte (-> AL)
		and	al,dl		; mask result
		cmp	al,ch		; is this value allowed?
		ja	RandMaxByte2	; invalid value, next attempt

; ------------- Pop registers

		pop	edx		; pop EDX
		pop	ecx		; pop ECX
RandMaxByte8:	ret

; -----------------------------------------------------------------------------
;           Get random signed byte with max value (with global seed)
; -----------------------------------------------------------------------------
; INPUT:	AL = maximal signed value (-128 to +127)
; OUTPUT:	AL = random byte (0 to maximal value)
; -----------------------------------------------------------------------------

RandMaxChar:	or	al,al		; is it unsugned value?
		jns	RandMaxByte	; it is unsigned value
		neg	al		; correct maximal value
		call	RandMaxByte	; generate random byte
		neg	al		; correct result
		ret

; -----------------------------------------------------------------------------
;           Get random unsigned word with max value (with global seed)
; -----------------------------------------------------------------------------
; INPUT:	AX = maximal unsigned value (0 to 65535)
; OUTPUT:	AX = random word (0 to maximal value)
; -----------------------------------------------------------------------------

; ------------- Check maximal value 0

RandMaxWord:	or	ax,ax		; maximal value is 0?
		jz	RandMaxWord8	; maximal value is 0

; ------------- Push registers

		push	ecx		; push ECX
		push	edx		; push EDX

; ------------- Prepare mask or maximal value

		bsr	cx,ax		; ECX <- bits of maximal value
		xor	edx,edx		; EDX <- 0
		mov	dl,B1		; EDX <- B1, maximal value bit
		shl	edx,cl		; EDX <- maximal value
		dec	edx		; DX <- mask of result
		xchg	ax,cx		; CX <- maximal value

; ------------- Find required value

RandMaxWord2:	call	RandWord	; get random word (-> AX)
		and	ax,dx		; mask result
		cmp	ax,cx		; is this value allowed?
		ja	RandMaxWord2	; invalid value, next attempt

; ------------- Pop registers

		pop	edx		; pop EDX
		pop	ecx		; pop ECX
RandMaxWord8:	ret

; -----------------------------------------------------------------------------
;           Get random signed word with max value (with global seed)
; -----------------------------------------------------------------------------
; INPUT:	AX = maximal signed value (-32768 to +32767)
; OUTPUT:	AX = random word (0 to maximal value)
; -----------------------------------------------------------------------------

RandMaxShort:	or	ax,ax		; is it unsugned value?
		jns	RandMaxWord	; it is unsigned value
		neg	ax		; correct maximal value
		call	RandMaxWord	; generate random word
		neg	ax		; correct result
		ret

; -----------------------------------------------------------------------------
;      Get random unsigned double word with max value (with global seed)
; -----------------------------------------------------------------------------
; INPUT:	EAX = maximal unsigned value (0 to 0ffffffffh)
; OUTPUT:	EAX = random double word (0 to maximal value)
; -----------------------------------------------------------------------------

; ------------- Check maximal value 0

RandMaxDWord:	cmp	eax,0ffffh	; only word number required?
		jbe	RandMaxWord	; generate word random number
		or	eax,eax		; maximal value is 0?
		jz	RandMaxDWord8	; maximal value is 0

; ------------- Push registers

		push	ecx		; push ECX
		push	edx		; push EDX

; ------------- Prepare mask or maximal value

		bsr	ecx,eax		; ECX <- bits of maximal value
		xor	edx,edx		; EDX <- 0
		mov	dl,B1		; EDX <- B1, maximal value bit
		shl	edx,cl		; EDX <- maximal value
		dec	edx		; EDX <- mask of result
		jnz	RandMaxDWord2	; mask is OK
		dec	edx		; EDX <- -1, maximal mask
RandMaxDWord2:	xchg	eax,ecx		; ECX <- maximal value

; ------------- Find required value

RandMaxDWord4:	call	RandDWord	; get random double word (-> EAX)
		and	eax,edx		; mask result
		cmp	eax,ecx		; is this value allowed?
		ja	RandMaxDWord4	; invalid value, next attempt

; ------------- Pop registers

		pop	edx		; pop EDX
		pop	ecx		; pop ECX
RandMaxDWord8:	ret

; -----------------------------------------------------------------------------
;        Get random signed double word with max value (with global seed)
; -----------------------------------------------------------------------------
; INPUT:	EAX = maximal signed value (-80000000h to +7fffffffh)
; OUTPUT:	EAX = random double word (0 to maximal value)
; -----------------------------------------------------------------------------

RandMaxLong:	or	eax,eax		; is it unsugned value?
		jns	RandMaxDWord	; it is unsigned value
		neg	eax		; correct maximal value
		call	RandMaxDWord	; generate random double word
		neg	eax		; correct result
		ret

; -----------------------------------------------------------------------------
;     Get random unsigned quadruple word with max value (with global seed)
; -----------------------------------------------------------------------------
; INPUT:	EDX:EAX = maximal unsigned value (0 to 0ffffffffffffffffh)
; OUTPUT:	EDX:EAX = random quadruple word (0 to maximal value)
; -----------------------------------------------------------------------------

; ------------- Check maximal value 0

RandMaxQWord:	or	edx,edx		; is maximal value QWORD?	
		jz	RandMaxDWord	; only DWORD required

; ------------- Push registers

		push	ebx		; push EBX
		push	ecx		; push ECX
		push	esi		; push ESI

; ------------- Prepare mask or maximal value

		bsr	ecx,edx		; ECX <- bits of maximal value HIGH
		xor	ebx,ebx		; EBX <- 0
		mov	bl,B1		; EBX <- B1, maximal value bit
		shl	ebx,cl		; EBX <- maximal value HIGH
		dec	ebx		; EBX <- mask of result HIGH
		jnz	RandMaxQWord4	; mask is OK
		dec	ebx		; EBX <- -1, maximal mask HIGH
RandMaxQWord4:	xchg	eax,ecx		; ECX <- maximal value LOW
		mov	esi,edx		; ESI <- maximal value HIGH

; ------------- Find required value

RandMaxQWord6:	call	RandQWord	; get random quadruple word (->EDX:EAX)
		and	edx,ebx		; mask result HIGH
		cmp	edx,esi		; check value HIGH
		jb	RandMaxQWord8	; value is OK
		ja	RandMaxQWord6	; invalid value, next attempt		
		cmp	eax,ecx		; check value LOW
		ja	RandMaxQWord6	; invalid value, next attempt

; ------------- Pop registers

RandMaxQWord8:	pop	esi		; pop ESI
		pop	ecx		; pop ECX
		pop	ebx		; pop EBX
		ret

; -----------------------------------------------------------------------------
;       Get random signed quadruple word with max value (with global seed)
; -----------------------------------------------------------------------------
; INPUT:	EDX:EAX = maximal signed value
; OUTPUT:	EDX:EAX = random quadruple word (0 to maximal value)
; -----------------------------------------------------------------------------

RandMaxInt64:	or	edx,edx		; is it unsugned value?
		jns	RandMaxQWord	; it is unsigned value
		neg	eax		; correct maximal value LOW
		adc	edx,byte 0	; carry
		neg	edx		; correct maximal value HIGH
		call	RandMaxQWord	; generate random double word
		neg	eax		; correct result LOW
		adc	edx,byte 0	; carry
		neg	edx		; correct result HIGH
		ret

; -----------------------------------------------------------------------------
;          Get random float with max value (9 digits, with global seed)
; -----------------------------------------------------------------------------
; INPUT:	ST0 = maximal value (can be signed)
; OUTPUT:	ST0 = random float (0 to max value, except)
; -----------------------------------------------------------------------------

RandMaxFloat:	call	RandFloat	; generate random float
		fmulp	st1,st0		; multiple with max. value
		ret	

; -----------------------------------------------------------------------------
;    Get random double float with max value (18 digits, with global seed)
; -----------------------------------------------------------------------------
; INPUT:	ST0 = maximal value (can be signed)
; OUTPUT:	ST0 = random double float (0 to max value)
; NOTES:	Due to rounding FPU results, it can reach max value.
; -----------------------------------------------------------------------------

RandMaxDouble:	call	RandDouble	; generate random double float
		fmulp	st1,st0		; multiple with max. value
		ret	

; -----------------------------------------------------------------------------
;               Get random byte in interval (with global seed)
; -----------------------------------------------------------------------------
; INPUT:	AL = maximal value (signed or unsigned)
;		AH = minimal value (signed or unsigned)
; OUTPUT:	AL = random byte (min to max)
; -----------------------------------------------------------------------------

RandIntByte:	sub	al,ah		; AL <- new maximal value
		call	RandMaxByte	; generate random byte
		add	al,ah		; AL <- add minimal value
		ret

; -----------------------------------------------------------------------------
;               Get random word in interval (with global seed)
; -----------------------------------------------------------------------------
; INPUT:	AX = maximal value (signed or unsigned)
;		DX = minimal value (signed or unsigned)
; OUTPUT:	AX = random word (min to max)
; -----------------------------------------------------------------------------

RandIntWord:	sub	ax,dx		; AX <- new maximal value
		call	RandMaxWord	; generate random word
		add	ax,dx		; AX <- add minimal value
		ret

; -----------------------------------------------------------------------------
;             Get random double word in interval (with global seed)
; -----------------------------------------------------------------------------
; INPUT:	EAX = maximal value (signed or unsigned)
;		EDX = minimal value (signed or unsigned)
; OUTPUT:	EAX = random double word (min to max)
; -----------------------------------------------------------------------------

RandIntDWord:	sub	eax,edx		; EAX <- new maximal value
		call	RandMaxDWord	; generate random double word
		add	eax,edx		; EAX <- add minimal value
		ret

; -----------------------------------------------------------------------------
;             Get random quadruple word in interval (with global seed)
; -----------------------------------------------------------------------------
; INPUT:	EDX:EAX = maximal value (signed or unsigned)
;		EBX:ECX = minimal value (signed or unsigned)
; OUTPUT:	EDX:EAX = random quadruple word (min to max)
; -----------------------------------------------------------------------------

RandIntQWord:	sub	eax,ecx		; EAX <- new maximal value LOW
		sbb	edx,ebx		; EDX <- new maximal value HIGH
		call	RandMaxQWord	; generate random quadruple word
		add	eax,ecx		; EAX <- add minimal value LOW
		adc	edx,ebx		; EDX <- add minimal value HIGH
		ret

; -----------------------------------------------------------------------------
;            Get random float in interval (9 digits, with global seed)
; -----------------------------------------------------------------------------
; INPUT:	ST0 = maximal value (can be signed)
;		ST1 = minimal value (can be signed)
; OUTPUT:	ST0 = random float (min to max)
; -----------------------------------------------------------------------------

RandIntFloat:	fsub	st0,st1		; subtract minimal value
		call	RandMaxFloat	; generate random float
		faddp	st1,st0		; random value
		ret	

; -----------------------------------------------------------------------------
;        Get random double float in interval (9 digits, with global seed)
; -----------------------------------------------------------------------------
; INPUT:	ST0 = maximal value (can be signed)
;		ST1 = minimal value (can be signed)
; OUTPUT:	ST0 = random double float (min to max)
; -----------------------------------------------------------------------------

RandIntDouble:	fsub	st0,st1		; subtract minimal value
		call	RandMaxDouble	; generate random double float
		faddp	st1,st0		; random value
		ret	

; -----------------------------------------------------------------------------
;           Generate Pseudo-Gaussian random number (with global seed)
; -----------------------------------------------------------------------------
; INPUT:	AL = level (0 to 255, 0=linear)
; OUTPUT:	ST0 = random double float (0 to 1)
; NOTES:	This random generator is not true Gaussian generator. It
;		generates random numbers with distribution which is near to
;		the Gaussian distribution. This is very simple algorithm:
;		it simple adds given number of random numbers. In results
;		there is minimal probability of values near 0 and 1 and
;		maximal probability of values near 0.5. Level value determines
;		steepness of the probability curve.
; -----------------------------------------------------------------------------
; Level 0:	Level 1:	Level 2:		Level 10:  X
; |		|       	|			|         XXX
; |		|      x	|        xXXXx		|        xXXXx
; |		|    xXXXx	|      XXXXXXXXX	|        XXXXX
; |XXXXXXXXXXX	|  xXXXXXXXx	|     XXXXXXXXXXX	|       xXXXXXx
; |XXXXXXXXXXX	|xXXXXXXXXXXXx	| xxXXXXXXXXXXXXXXXxx	|    xxXXXXXXXXXxx
; +-----------	+-------------	+---------------------	+----------------------
; -----------------------------------------------------------------------------

; ------------- Push registers

RandGauss:	push	ecx		; push ECX

; ------------- Prepare level

		movzx	ecx,al		; ECX <- required level
		inc	ecx		; ECX <- number of random numbers
		push	ecx		; push ECX, count of numbers

; ------------- Add random numbers

		fldz			; load zero to ST0
RandGauss2:     call	RandDouble	; generate random double float number
		faddp	st1,st0		; add number to accumulator
		loop	RandGauss2	; next value

; ------------- Divide accumulator with count of numbers

		fidiv	dword [esp]	; divide with count of numbers
		pop	ecx		; destroy ECX from the stack

; ------------- Pop registers

		pop	ecx		; pop ECX
		ret

; -----------------------------------------------------------------------------
;                                   Data
; -----------------------------------------------------------------------------

		DATA_SECTION

; ------------- Global seed for random generator
; Global seed is initialized in INIT\INIT.ASM and incremented with events.

		align	4, db 0
RandSeed:	dd	5623489		; seed for global random generator

; ------------- Float coefficient 1/100000000h

		align	4, db 0
RandFltCoef:	dd	0.00000000023283064365386962890625

; ------------- Double float coefficient 1/8000000000000000h

		align	8, db 0
RandDblCoef:	dq	1.0842021724855044340074528008699e-19

; -----------------------------------------------------------------------------
;                            Uninitialized data
; -----------------------------------------------------------------------------

		BSS_SECTION

Back to source browser