# random values

hi
i have coded a routine for random numbers. its nice, but slow
because of 'in al,40h'. if u have better code or algo please post.

here is my code for tasm:
[code]
model tiny,pascal
locals

.code
.386
org 100h
main:
mov ax,13h
int 10h
again:
CALL rand,offset X,0,319
CALL rand,offset Y,0,199
CALL randb,offset COL,0,255

CALL pix,0a000h,X,Y,word ptr COL

in al,60h
dec al
jnz again

mov ax,03h
int 10h
ret

;*****************************************************************************
; calculates a random- word- number. please do not request such funny *
; intervals like 0- 0 or 123- 123. *
; IN: ofsVAR = near pointer to a word in memory where the number should be *
; returned to. *
; min = the lowest value that might be returned *
; max = the highest value that might be returned *
;*****************************************************************************
rand proc near uses eax ebx edx di,ofsVAR,min,max : word
.386
xor eax,eax
xor ebx,ebx
xor edx,edx
mov ax,cs:[seed]
mov bx,cs:[seed]
xchg bh,bl
sub bx,cs:[seed]
mov bl,ah
mov ah,bh
xchg ah,al
in al,40h
xchg ah,al
mov cs:[seed],ax
mov bh,al
mov ax,bx
mov bx,[max]
sub bx,[min]
inc ebx
div ebx
mov di,[ofsVAR]
mov word ptr [di],dx
ret
.8086
seed dw 1234h
rand endp

;*****************************************************************************
; calculates a random- byte- number. please do not request such funny*
; intervals like 0- 0 or 123- 123. *
; IN: ofsVAR = near pointer to a byte in memory where the number should be *
; returned to. *
; min = the lowest value that might be returned *
; max = the highest value that might be returned *
;*****************************************************************************
randb proc near uses ax bx dx di,ofsVAR,min,max : word
inc [max]
mov ax,cs:[seed]
mov bx,cs:[seed]
xchg bh,bl
sub bx,cs:[seed]
mov bl,ah
mov ah,bh
xchg ah,al
in al,40h
sub ax,cs:[seed]
xchg ah,al
sub cs:[seed],ax
mov bh,al
mov ax,bx
mov bx,[max]
sub bx,[min]
xor dx,dx
div bx
mov di,[ofsVAR]
mov byte ptr [di],dl
ret
randb endp

pix proc near uses ax bx es,SEGM,X1,Y1 : word, COL1 : word
.286
mov ax,[SEGM]
mov es,ax
mov ax,[Y1]
mov bx,[X1]
xchg ah,al
shr ax,2
mov al,byte ptr [COL1]
mov es:[bx],al
.8086
ret
pix endp

X dw ?
Y dw ?
COL db ?

end main
[/code]

• I always use the timer port for random values, here's an elaborate version of it. Too bad it chokes the pipeline....

[code]
;Input: Nothing
;Output: EAX=Random number
;Destroyed: DS, SI, EAX, ECX, EBX
RandomNum PROC
in al,40h
mov ah,al
in al,40h
mov ds,ax
shl eax,16
in al,40h
mov ah,al
in al,40h
mov ebx,eax
mov si,ax
mov dx,ax
lds si,[si]
in eax,dx
xor eax,ebx
xor eax,ecx
xor eax,[si]
ret
RandomNum ENDP
[/code]
• : I always use the timer port for random values, here's an elaborate version of it. Too bad it chokes the pipeline....

yea, i use the timer port either, but this is the problem. the port
reading makes the procedure slow. this is why i'm looking for other
solutions.
• [code]
; ----------------------------------------------------------------------------
; FILE: Random.Asm
; DATE: December 19, 2001
; DESCRIPTION: Random number generation.
; ----------------------------------------------------------------------------

.386

; --- Includes:

; --- Externals:

; --- Publics:
Public RandomRange
Public Random
Public RandomSeed
Public Random1024

; ----------------------------------------------------------------------------
Data Segment Use16 Dword Public 'DATA'
Assume Ds:Data

wNextRandom Dw 817
wRandSeed Dw 0
Data EndS

; ----------------------------------------------------------------------------
Code Segment Use16 Dword Public 'CODE'
Assume Cs:Code

Random1024 Proc Near
; ----------------------------------------------------------------------------
; OUTPUT: AX -> random number in range [0..1023]
; ----------------------------------------------------------------------------
push ecx
push edx

movzx eax, wNextRandom
mov ecx, 217
mul ecx
mov ecx, 1024
div ecx
mov wNextRandom, dx
mov ax, dx

pop edx
pop ecx
ret
Random1024 EndP

; ----------------------------------------------------------------------------
RandomSeed Proc Near
push ax
push cx
push dx

mov ah, 2Ch
int 21h
xor dh, dl
movzx cx, dh
inc cx

@_SeedInProgress:
call Random1024
loop @_SeedInProgress

pop dx
pop cx
pop ax
ret
RandomSeed EndP

Random Proc Near
; ----------------------------------------------------------------------------
; INPUT: DX <- enumerator value
; OUTPUT: AX -> random value in range [0..DX-1]
; ----------------------------------------------------------------------------
push cx
push dx

call Random1024
mov cx, dx
xor dx, dx
div cx
mov ax, dx

pop dx
pop cx
ret
Random EndP

RandomRange Proc Near
; ----------------------------------------------------------------------------
; INPUT:
; CX <- range begin
; DX <- range end
; OUTPUT:
; AX -> random value in range [CX..DX] inclusive
; ----------------------------------------------------------------------------
push dx
sub dx, cx
inc dx
call Random
pop dx
ret
RandomRange EndP

Code EndS
End
[/code]
• Well with huge ass rotuine like those, everything is bound to be slow. You might want to try optimizing your routines before worrying about simple problems like reading ports. Also, read about the RDTSC instruction. It is an almost undocumented instruction that reads the number of CPU clock cycles elapsed since start up.

--------------------------------------------
I will bend your mind with my spoon...

• RDTSC is good for Pentium+'s, but not 486's and below. It and the PIT aren't really that random, that's why I'd also read random memory cells and ports and use XOR to randomize the number some more. Random number generation isn't used all that often anyway and people usually care more about good random number generation.
• [b][red]This message was edited by Puzzler at 2002-8-15 8:9:28[/red][/b][hr]
Actually it is pretty good. In windows, its great because you never know how many cycles are stolen by the OS and other progs. For me it's good because I wait for the timer often in my little demo so it's pretty good. Also, it generates number based on when the program starts and therefore is dependent on the user. Besides, it's at elast good for a seed because there are no port reads, no memory reads, no loops, and no other slowdowns and it is only 2 bytes. Yoiu could use it in your prog by itself for a random number generator if you wanted to skip a 3 byte call, having a routine at the end of the program, and a lot of overhead for the call.

Now to tell you, the problem with reading ports is that you might read a value off of a queue or stack and fubar a program.

--------------------------------------------
I will bend your mind with my spoon...

• the port read IS the problem.
i didn't try ur routine, but i dont think that its usefull in a loop
cause it'll give me almost the same number on the next loop.