I'm trying to create a program that generate 4 random numbers, insert them into array and then print them, but the problem is that it insert always the same numbers because I generate the number with the clock and it's too fast, this is my code:
IDEAL
MODEL small
STACK 100h
DATASEG
Clock equ es:6Ch
EndMessage db 'Done',13,10,'$'
divisorTable db 10,1,0
randoms db 4 dup(11)
CODESEG
proc printNumber
push ax
push bx
push dx
mov bx,offset divisorTable
nextDigit:
xor ah,ah ; dx:ax = number
div [byte ptr bx] ; al = quotient, ah = remainder
add al,'0'
call printCharacter ; Display the quotient
mov al,ah ; ah = remainder
add bx,1 ; bx = address of next divisor
cmp [byte ptr bx],0 ; Have all divisors been done?
jne nextDigit
mov ah,2
mov dl,13
int 21h
mov dl,10
int 21h
pop dx
pop bx
pop ax
ret
endp printNumber
proc printCharacter
push ax
push dx
mov ah,2
mov dl, al
int 21h
pop dx
pop ax
ret
endp printCharacter
start:
mov ax, @data
mov ds, ax
; initialize
mov ax, 40h
mov es, ax
mov cx, 4
mov bx, offset randoms
RandLoop:
; generate random number, cx number of times
mov ax, [Clock] ; read timer counter
mov ah, [byte cs:bx] ; read one byte from memory
xor al, ah ; xor memory and counter
and al, 00001111b ; leave result between 0-15
mov [bx],al ;move the random number to the array
inc bx
loop RandLoop
; print exit message
mov cx, 4
mov bx, offset randoms
PrintOptions:
mov dl,[bx]
call printNumber
inc bx
loop PrintOptions
mov dx, offset EndMessage
mov ah, 9h
int 21h
exit:
mov ax, 4c00h
int 21h
END start
I think that the problem is here:
RandLoop:
; generate random number, cx number of times
mov ax, [Clock] ; read timer counter
mov ah, [byte cs:bx] ; read one byte from memory
xor al, ah ; xor memory and counter
and al, 00001111b ; leave result between 0-15
mov [bx],al ;move the random number to the array
inc bx
;call printNumber
loop RandLoop
This is a classic XY problem . Your problem is that you're not getting good randomly-generated numbers, so you think the solution is to insert a delay. That is not a good solution.
First of all, it won't really solve your problem. The system clock is not a random number generator. There is nothing "random" about the time. The only thing that the time is useful for is as a "seed" for a random number generator. A "seed" is just the starting value. You use it only once, when your application first starts up, to prime the random number generator. You don't use the time each time you need a random number, so it doesn't matter what the actual time is.
The second reason why inserting a delay is not a good solution is because there's no reliable way to insert a delay. Programmers used to do things like this back in the '80s, and that's why many old games won't run on modern machines: they had hard-coded timing loops that made empirical assumptions about the performance of the underlying processor. There is one reliable way to insert a delay by programming the timer interrupt, but that doesn't work under operating systems, so it's generally a non-starter today.
The real solution here is to use a better random-number generator. Every C standard library provides one, but if you don't have a C standard library handy (or don't want to link to one), then it isn't that hard to write one yourself in assembly.
ANSI C essentially suggests the following implementation for a random number generator:
extern unsigned long seed;
return ((seed = seed * 1103515245 + 12345) >> 16) & 0x7FFF;
and that's what most C standard libraries have traditionally used. It's not horrible, but it's not great, either. The biggest problem with it is that it returns only 15 bits. If we're writing it in assembly, we can make use of the 64-bit intermediates generated by 32-bit integer multiplication and extend the result to 32 bits instead. This results in an extremely fast PRNG implementation, capable of generation millions of values per second, and its "randomness" is actually pretty solid. It passes a simple chi-square test, and when you use it to plot a dot pattern, things "look random".
Here's what the code would look like:
RNG_Seed DD ?
; Generates a pseudo-random 32-bit number.
; Parameters: <none>
; Clobbers: EAX, EDX
; Returns: EAX contains the random number
GenerateRandNum PROC
mov eax, DWORD PTR [RNG_Seed] ; get last seed value
mov edx, 1103515245 ; get multiplier
mul edx ; do multiplication
shl edx, 16 ; move into high 16 bits
add eax, 12345 ; do addition
adc edx, 0FFFFh ; carry to high
mov DWORD PTR [RNG_Seed], eax ; store this seed
shr eax, 16 ; discard low 16 bits
and edx, 0FFFF0000h ; mask high 16 bits
or eax, edx ; combine those bits
ret ; and return them
GenerateRandNum ENDP
To use it, store the current time into RNG_Seed
when your application starts up. From then on, just call the GenerateRandNum
procedure, and it will return a 32-bit random number in EAX
. Don't touch RNG_Seed
again (it is maintained internally by GenerateRandNum
).
There are better pseudo-random-number generators out there, but this one should be more than good enough.
Of course, after I write this answer, I notice that you are using 16-bit assembly. If that implies you're targeting a processor older than the 386 (such as the 8088/8086), you will not be able to do 32-bit multiplication. In that case, you would probably just go back to the C implementation, with its 15-bit result:
RNG_Seed DW ?
; Generates a pseudo-random 15-bit number.
; Parameters: <none>
; Clobbers: AX, DX
; Returns: AX contains the random number
GenerateRandNum PROC
push bx
push cx
push si
push di
; 32-bit multiplication in 16-bit mode (DX:AX * CX:BX == SI:DI)
mov ax, WORD PTR [RNG_Seed]
xor dx, dx
mov cx, 041C6h
mov bx, 04E6Dh
xor di, di
push ax
mul bx
mov si, dx
xchg di, ax
mul bx
add si, ax
pop ax
mul cx
add si, ax
; Do addition
add di, 3039h
adc si, 0
; Save seed
mov WORD PTR [RNG_Seed], di
; Get result and mask bits
mov ax, si
and ah, 07Fh
pop di
pop si
pop cx
pop bx
ret
GenerateRandNum ENDP
You can find plenty more discussion about pseudo-random number generators on Wikipedia , including some links to alternative implementations. Or see the question vitsoft linked, which has answers discussing the middle-square method, which is relatively simple.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.